<?xml version="1.0" encoding="UTF-8"?>
  <feed xmlns="http://www.w3.org/2005/Atom">
    <title>Elixir Alchemy by AppSignal</title>
    <subtitle>Dive deep into all things Elixir. If you are interested in learning more about concurrency, webservers, memory allocations and garbage collection, you'll love this.</subtitle>
    <id>https://blog.appsignal.com</id>
    <link href="https://blog.appsignal.com"/>
    <link href="https://blog.appsignal.com/elixir-alchemy-feed.xml" rel="self"/>
    <updated>2026-06-08T10:00:00+00:00</updated>
    <author>
      <name>Roy Tomeij</name>
    </author>
    
  <entry>
    <title>Debugging Slow Ecto Queries with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2026/04/02/debugging-slow-ecto-queries-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2026/04/02/debugging-slow-ecto-queries-with-appsignal.html</id>
    <published>2026-04-02T00:00:00+00:00</published>
    <updated>2026-04-02T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn how to use AppSignal to identify and fix slow Ecto queries in your Elixir applications.</summary>
    <content type="html">&lt;p&gt;A sports car can only be driven as fast as the road it&amp;#39;s driven on. If you&amp;#39;re stuck behind a tractor on a single-lane road, you&amp;#39;re not going anywhere fast. The same idea applies to web performance: your application&amp;#39;s throughput is only as fast as it&amp;#39;s slowest bottleneck.&lt;/p&gt;
&lt;p&gt;For Phoenix applications, that bottleneck is almost always the database. &lt;a href=&quot;https://github.com/elixir-ecto/ecto&quot;&gt;Ecto&lt;/a&gt; provides powerful tools that allow us to compose large, readable queries by chaining functions together, but this readability can come at the cost of expensive queries under the hood. Slow queries, unindexed tables, and &lt;em&gt;N+1&lt;/em&gt; requests affect your app&amp;#39;s performance.&lt;/p&gt;
&lt;p&gt;Finding and resolving these issues can take a lot of work, but as the title suggests, &lt;a href=&quot;https://appsignal.com/&quot;&gt;AppSignal&lt;/a&gt; can be the roadside assistance you need to get your app back on the road. We&amp;#39;ll first look at how AppSignal detects poorly performing queries, then look at understanding why those queries are slow, and then finally fixing the problems.&lt;/p&gt;
&lt;h2&gt;Finding the Slow Query in AppSignal&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s one thing to know your app has a traffic jam, and quite another to know
where that traffic jam exists. Because AppSignal auto-instruments Ecto queries,
it&amp;#39;s able to both pinpoint where in your app that bottleneck is occurring as
well as point out the problematic query itself.&lt;/p&gt;
&lt;p&gt;To demonstrate how AppSignal helps identify bottlenecks, we’ll use an example app that mimics a basic social media site, with users, followers and posts. When visiting a user&amp;#39;s profile page (&lt;code&gt;/users/:username&lt;/code&gt;) the app displays counts of followers
and those they follow, who they follow and who follows them, and finally a list
of posts from those they follow.&lt;/p&gt;
&lt;p&gt;The example app and code used in this article can be found on the GitHub &lt;a href=&quot;https://github.com/samullen/as-social&quot;&gt;Social app
repo&lt;/a&gt;. Basic instructions for &lt;a href=&quot;https://docs.appsignal.com/elixir/installation&quot;&gt;installing AppSignal in Elixir apps&lt;/a&gt;, and a more &lt;a href=&quot;https://blog.appsignal.com/2024/09/17/a-complete-guide-to-phoenix-for-elixir-monitoring-with-appsignal.html&quot;&gt;complete guide&lt;/a&gt; are also available.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03/social-screenshot.png&quot; alt=&quot;Social Screenshot&quot; title=&quot;Social app profile page&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Although the page appears to be functioning correctly, AppSignal has alerted us to a performance issue that hasn&amp;#39;t yet risen to the point of user complaints, and it&amp;#39;s done so
in three different places under the &lt;em&gt;Performance&lt;/em&gt; navigation section:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Issue list&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Actions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slow queries&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Issue list&lt;/em&gt;, as the name implies, lists issues your app is currently
experiencing. In our social app, we can see that our &lt;code&gt;/users/:username&lt;/code&gt; endpoint
is already listed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03/issues-list.png&quot; alt=&quot;Issues list&quot; title=&quot;AppSignal issues list&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;Actions&lt;/em&gt; tab provides a list of routes along with their duration (mean and P90) and throughput. Using this page, you can sort routes based on their duration, and then click into the laggard routes to find more information. Clicking into our &lt;code&gt;/users/:username&lt;/code&gt; route reveals that there is an open &amp;quot;Performance incident.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03/performance-incident.png&quot; alt=&quot;Performance incident&quot; title=&quot;AppSignal performance incident&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Lastly, we can see which queries are causing the most problems under the &lt;em&gt;Slow
queries&lt;/em&gt; tab. By default, AppSignal ranks queries by their &lt;em&gt;impact&lt;/em&gt; (i.e.
frequency * duration) to performance from greatest to least. You&amp;#39;ll note that
what is listed is the SQL queries themselves, not the Ecto functions or from
where in the app they originate.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03/query-impact.png&quot; alt=&quot;Query impact&quot; title=&quot;AppSignal slow queries tab ranked by impact&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Understanding Why It&amp;#39;s Slow&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s not always easy to track performance issues, but the &lt;a href=&quot;https://docs.appsignal.com/api/samples.html&quot;&gt;Samples&lt;/a&gt; tool in AppSignal simplifies the process by mapping out each operation in the &lt;em&gt;Timeline&lt;/em&gt; view. The visualization it provides enables you to pinpoint the specific Ecto calls responsible for bottlenecks.&lt;/p&gt;
&lt;p&gt;You can get to this page by first navigating to the &lt;em&gt;Issue list&lt;/em&gt; under the &lt;em&gt;Performance&lt;/em&gt; navigation section, and clicking on an &amp;quot;action&amp;quot; you want to explore. From there, click on the specific sample you&amp;#39;re interested in from the &lt;em&gt;Samples&lt;/em&gt; section.&lt;/p&gt;
&lt;p&gt;Once you&amp;#39;re on the &lt;em&gt;Samples&lt;/em&gt; page, scroll down to the &lt;em&gt;Timeline&lt;/em&gt; section. You
should see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03/appsignal-timeline.png&quot; alt=&quot;AppSignal timeline&quot; title=&quot;AppSignal timeline view&quot;/&gt;&lt;/p&gt;
&lt;p&gt;What&amp;#39;s most noticeable in the timeline is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Three queries are greater than or equal to 1 ms&lt;/li&gt;
&lt;li&gt;One query takes up the majority of the time&lt;/li&gt;
&lt;li&gt;There are six queries, but the code (not shown) only calls five functions
(indicating a potential N+1 query)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can get more information on each of the queries by hovering over any of the
events. If it&amp;#39;s a performance issue, we can then use the &lt;code&gt;explain&lt;/code&gt; function
common in most relational databases to investigate what&amp;#39;s happening.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03/samples-sql.png&quot; alt=&quot;Samples with SQL&quot; title=&quot;AppSignal timeline with SQL query details&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;explain analyze&lt;/code&gt; on the SQL shown above results in the &amp;quot;Query
Plan&amp;quot; shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                                                          QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
 Sort  (cost=106.72..107.47 rows=300 width=127) (actual time=2.782..2.894 rows=1500 loops=1)
   Sort Key: p0.inserted_at DESC
   Sort Method: quicksort  Memory: 275kB
   -&amp;gt;  Hash Join  (cost=2.17..94.37 rows=300 width=127) (actual time=0.496..1.873 rows=1500 loops=1)
         Hash Cond: (f1.followed_id = u2.id)
         -&amp;gt;  Hash Join  (cost=1.07..91.66 rows=300 width=91) (actual time=0.164..1.102 rows=1500 loops=1)
               Hash Cond: (p0.user_id = f1.followed_id)
               -&amp;gt;  Seq Scan on posts p0  (cost=0.00..82.00 rows=2000 width=83) (actual time=0.105..0.504 rows=2000 loops=1)
               -&amp;gt;  Hash  (cost=1.06..1.06 rows=1 width=8) (actual time=0.027..0.028 rows=3 loops=1)
                     Buckets: 1024  Batches: 1  Memory Usage: 9kB
                     -&amp;gt;  Seq Scan on followers f1  (cost=0.00..1.06 rows=1 width=8) (actual time=0.019..0.020 rows=3 loops=1)
                           Filter: (follower_id = 30)
                           Rows Removed by Filter: 3
         -&amp;gt;  Hash  (cost=1.04..1.04 rows=4 width=44) (actual time=0.308..0.309 rows=4 loops=1)
               Buckets: 1024  Batches: 1  Memory Usage: 9kB
               -&amp;gt;  Seq Scan on users u2  (cost=0.00..1.04 rows=4 width=44) (actual time=0.012..0.013 rows=4 loops=1)
 Planning Time: 0.315 ms
 Execution Time: 3.360 ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things stand out in this plan:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We&amp;#39;re scanning many more records than
necessary (&lt;code&gt;Seq Scan on posts...rows=2000&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The estimated rows (300) vs the
actual rows (1,500) are significantly different which can lead to the database
choosing the wrong strategy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A potential third item might be the &lt;code&gt;Filter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see what we can do to improve the performance.&lt;/p&gt;
&lt;p&gt;&lt;Banner
  title=&quot;See how AppSignal can help you optimize your Elixir app&quot;
  buttonText=&quot;Start monitoring your app&quot;
  buttonHref=&quot;https://appsignal.com/users/sign_up?utm_source=blog&amp;utm_medium=article&amp;utm_campaign=debugging_slow_ecto_queries_with_appsignal_2026_03_30&amp;utm_content=banner_signup&quot;
  buttonGoal=&quot;debugging_slow_ecto_queries_with_appsignal_banner_signup&quot;
/&gt;&lt;/p&gt;
&lt;h2&gt;Common Ecto Fixes&lt;/h2&gt;
&lt;p&gt;In his article, &lt;a href=&quot;https://blog.appsignal.com/2023/05/23/tackling-performance-issues-in-ecto-applications.html&quot;&gt;Tackling Performance Issues in Ecto Applications&lt;/a&gt;, &lt;a href=&quot;https://blog.appsignal.com/authors/marcos-ramos.html&quot;&gt;Marcos Ramos&lt;/a&gt; addresses
several issues affecting performance. The two we&amp;#39;re most interested in are &amp;quot;Inefficient Queries in Ecto&amp;quot; and &amp;quot;The N+1 Query Problem&amp;quot;.&lt;/p&gt;
&lt;h3&gt;Inefficient Queries in Ecto&lt;/h3&gt;
&lt;p&gt;Not all performance wins require the same level of effort. When tackling inefficiencies in Ecto queries, consider the following possible optimizations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure the tables are indexed correctly&lt;/li&gt;
&lt;li&gt;Only ask for what you need&lt;/li&gt;
&lt;li&gt;Offload the heavy lifting to views or processes that are better able to handle the work&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Validating tables are properly indexed is a great place to start. Adding indexes which should have existed from the beginning (e.g. on foreign keys, sortable fields, and commonly filtered fields) will always bring an improvement to performance. In our example, indexes on &lt;code&gt;posts.user_id&lt;/code&gt;,&lt;code&gt;followers.follower_id&lt;/code&gt;, &lt;code&gt;followers.followed_id&lt;/code&gt;, and &lt;code&gt;posts.inserted_at&lt;/code&gt; have all been erroneously forgotten.&lt;/p&gt;
&lt;p&gt;The fix is simply creating those indexes with an Ecto migration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Social.Repo.Migrations.AddMissingIndexes do
  use Ecto.Migration

  def change do
    create index(:posts, [:user_id])
    create index(:posts, [:inserted_at])
    create index(:followers, [:follower_id])
    create index(:followers, [:followed_id])
    create index(:followers, [:inserted_at])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You would normally create a migration for each index or at least group them by affected table.&lt;/p&gt;
&lt;p&gt;After making sure your tables are properly indexed, another great tip is to check for “unbound queries”. As the name suggests, unbound queries are those queries which have no constraints. Examples might include queries that don&amp;#39;t limit the number of returned rows, aren&amp;#39;t constrained by a &lt;code&gt;where/3&lt;/code&gt; clause, or don&amp;#39;t use &lt;code&gt;select/3&lt;/code&gt; to limit the fields returned.&lt;/p&gt;
&lt;p&gt;As we saw above, our query plan showed that we were working with 2,000 results. We don&amp;#39;t need to see that many posts at once, so it makes sense to limit the number of posts per &amp;quot;page&amp;quot;. To that end, we&amp;#39;ll add both &lt;code&gt;limit/3&lt;/code&gt; and &lt;code&gt;offset/3&lt;/code&gt; to our query below.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def list_feed_posts(user_id, page \\\\ 1, page_size \\\\ 20) do
  from(p in Post,
    join: f in Social.Users.Follower,
    on: f.follower_id == ^user_id and f.followed_id == p.user_id,
    join: u in assoc(p, :user),
    order_by: [desc: p.inserted_at],
    preload: [user: u],
    limit: ^page_size,
    offset: ^page_size * (^page - 1)
  )
  |&amp;gt; Repo.all()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are still seeing performance issues after indexing tables and constraining the data returned, you may need to consider moving your more complex queries into materialized
views or to a background job. Aggregated stats, dashboard metrics, multi-join filtering, long-running reports, and data-exports are all examples of queries or processes which can take advantage of these types of enhancements.&lt;/p&gt;
&lt;h3&gt;The N+1 Query Problem&lt;/h3&gt;
&lt;p&gt;As Marcos explains in his article, N+1 queries occur &amp;quot;when an application loads a parent record and its associated child records in separate queries.&amp;quot; In our app that might be by first pulling a list of people followed and &lt;em&gt;then&lt;/em&gt; retrieving their posts in separate queries. The &lt;code&gt;1&lt;/code&gt; represents the initial query, while the &lt;code&gt;N&lt;/code&gt; represents each consecutive query.&lt;/p&gt;
&lt;p&gt;In our example app, what originally looked like an N+1 query was the result of a single function issuing two &lt;code&gt;count&lt;/code&gt; queries, and doesn&amp;#39;t need improvement:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def get_user_follow_counts(user_id) do
  follower_count =
    from(f in Follower,
      where: f.followed_id == ^user_id,
      select: count(f.id)
    )
    |&amp;gt; Repo.one()

  following_count =
    from(f in Follower,
      where: f.follower_id == ^user_id,
      select: count(f.id)
    )
    |&amp;gt; Repo.one()

  %{followers: follower_count, following: following_count}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to understand N+1 queries more, &lt;a href=&quot;https://blog.appsignal.com/authors/sapan-diwakar.html&quot;&gt;Sapan Diwakar&lt;/a&gt; has a great tutorial on how to &lt;a href=&quot;https://blog.appsignal.com/2024/10/08/find-and-fix-n-plus-1-queries-using-appsignal-for-a-phoenix-app-in-elixir.html&quot;&gt;Find and Fix N+1 Queries Using AppSignal&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Verifying Our Changes Worked&lt;/h2&gt;
&lt;p&gt;Once you have found and eliminated the speed bumps slowing you down, you&amp;#39;ll want
to verify that your changes actually fixed the problems. You&amp;#39;ll first want to
verify your changes locally, but once you&amp;#39;ve deployed, make sure to review your
project&amp;#39;s AppSignal page to confirm that your changes are having the effect
you&amp;#39;re expecting. You can do that by navigating to the route from the &lt;em&gt;Actions&lt;/em&gt;
page.&lt;/p&gt;
&lt;p&gt;Note the &lt;a href=&quot;https://docs.appsignal.com/application/markers/deploy-markers.html&quot;&gt;Deploy markers&lt;/a&gt; below the timeline. These are &lt;a href=&quot;https://docs.appsignal.com/guides/deploy-markers.html#elixir&quot;&gt;trivial to set up&lt;/a&gt; and will help you identify when changes took effect, and which commit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-03/optimized.png&quot; alt=&quot;Deploy markers in performance timeline&quot; title=&quot;AppSignal deploy markers in performance timeline&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can even drill into the latest &lt;em&gt;Samples&lt;/em&gt; to see how your
changes affected specific queries against production data.&lt;/p&gt;
&lt;h2&gt;Wrap-Up&lt;/h2&gt;
&lt;p&gt;Sports cars are loads of fun to drive on long straightaways, around tight
curves, and sometimes even on unpoliced country roads. They&amp;#39;re less fun to drive
in bad weather or through construction areas. It&amp;#39;s a similar experience for your
app&amp;#39;s users. Speed matters and if your app isn&amp;#39;t responsive enough, your users
may decide to get off at the next exit.&lt;/p&gt;
&lt;p&gt;To avoid that, we first looked at how to use AppSignal to detect and find slow
queries, primarily focused on the &lt;em&gt;Performance&lt;/em&gt; navigation section and the tools
under it: &lt;em&gt;Issue list&lt;/em&gt;, &lt;em&gt;Actions&lt;/em&gt;, and &lt;em&gt;Slow queries&lt;/em&gt;. Next, we used the
&lt;em&gt;Timeline&lt;/em&gt; view within an individual &amp;quot;sample&amp;quot; to isolate potential causes. This
gave us a closer look at the request lifecycle, exposing N+1 queries and the
underlying SQL responsible for the lag. Finally, we reviewed common fixes
(adding indexes, constraining queries, etc.) and how to verify our fixes worked.&lt;/p&gt;
&lt;p&gt;Phoenix gives you speed by default. Don&amp;#39;t let a bad query or a poorly indexed
table turn your sports car into an old clunker.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Domains and Resources in Ash for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2026/01/13/domains-and-resources-in-ash-for-elixir.html"/>
    <id>https://blog.appsignal.com/2026/01/13/domains-and-resources-in-ash-for-elixir.html</id>
    <published>2026-01-13T00:00:00+00:00</published>
    <updated>2026-01-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">If you’ve been on the fence about trying the Ash Framework, this post is for you.</summary>
    <content type="html">&lt;p&gt;If you’ve been on the fence about trying the Ash Framework, this post is for you.&lt;/p&gt;
&lt;p&gt;We’re going to explore why Ash is a game changer for Elixir developers by building something complex, real, but surprisingly elegant.&lt;/p&gt;
&lt;p&gt;We’ll create AshTherapy, an AI-powered therapeutic chat service that handles conversations, messages, and user interactions — all powered by Ash.&lt;/p&gt;
&lt;p&gt;Before we go further, let’s first answer the question: what exactly is Ash?&lt;/p&gt;
&lt;h2&gt;What Is Ash for Elixir?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/ash/readme.html&quot;&gt;Ash&lt;/a&gt; is a business domain modeling framework for Elixir.
It works seamlessly with Phoenix to simplify the part of our app that deals with &lt;em&gt;business logic&lt;/em&gt; — our data, relationships, and rules.&lt;/p&gt;
&lt;p&gt;Think of it like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phoenix handles the technical layer — HTTP, sockets, and controllers.&lt;/li&gt;
&lt;li&gt;Ash handles the business layer — entities, relationships, and actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Together, they help us build fast and model correctly, with less boilerplate and more focus on what really matters.&lt;/p&gt;
&lt;h2&gt;The AshTherapy Use Case&lt;/h2&gt;
&lt;p&gt;Now that we know what Ash is, let’s see it in action.
We’ll bring the concepts of domains and resources to life through our demo app, AshTherapy.&lt;/p&gt;
&lt;p&gt;Here’s how it works:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A user visits the site and starts a new conversation.&lt;/li&gt;
&lt;li&gt;They set a goal or motive — for example, “I want to handle work stress better.”&lt;/li&gt;
&lt;li&gt;They then exchange messages with an AI companion that responds thoughtfully.&lt;/li&gt;
&lt;li&gt;This back-and-forth continues, forming a guided digital therapy session.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2026-01/ashtherapy.png&quot; alt=&quot;AshTherapy - AI-powered therapeutic chat service&quot;/&gt;&lt;/p&gt;
&lt;p&gt;To model this in Ash, we’ll define three key resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;User&lt;/code&gt; — the person using the service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Conversation&lt;/code&gt; — the therapy session container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Message&lt;/code&gt; — each exchange in the session (user or AI)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All three live inside a single domain: &lt;code&gt;AshTherapy.Therapy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this first post, we’ll focus on defining these resources and understanding how the domain ties them together.&lt;/p&gt;
&lt;h2&gt;Check Out the Code&lt;/h2&gt;
&lt;p&gt;Before we dive deeper, a quick note. In this post, we won’t walk through how to create an Ash domain or resource step-by-step — that part is already well covered in the official documentation.&lt;/p&gt;
&lt;p&gt;Our focus here is on understanding what domains and resources &lt;em&gt;mean&lt;/em&gt; in Ash and how they work together, which is even more important when we’re just getting started.&lt;/p&gt;
&lt;p&gt;If we check out the &lt;a href=&quot;https://github.com/devcarrots/ash_therapy&quot;&gt;AshTherapy codebase&lt;/a&gt; (branch: &lt;code&gt;post-1&lt;/code&gt;), we’ll find everything set up and ready to follow along with the examples in this post. We’ll take time here to explain the code in that project.&lt;/p&gt;
&lt;p&gt;To learn how to create a new domain or resource from scratch, we can refer to the official &lt;a href=&quot;https://hexdocs.pm/ash/Mix.Tasks.Ash.html&quot;&gt;Ash HexDocs&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/ash/Mix.Tasks.Ash.Gen.Domain.html&quot;&gt;Create a new domain&lt;/a&gt; using:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix ash.generate.domain MyApp.MyDomain
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/ash/Mix.Tasks.Ash.Gen.Resource.html&quot;&gt;Create a new resource&lt;/a&gt; using:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix ash.generate.resource MyApp.MyDomain.MyResource
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that out of the way, let’s explore the User, Conversation, and Message resources that make up our &lt;code&gt;AshTherapy&lt;/code&gt; domain.&lt;/p&gt;
&lt;h2&gt;Ash Domains&lt;/h2&gt;
&lt;p&gt;An &lt;a href=&quot;https://hexdocs.pm/ash/Ash.Domain.html&quot;&gt;Ash domain&lt;/a&gt; is a logical container that groups related resources together.
It keeps our business logic organized and provides a clean boundary for everything that belongs to a specific part of our application — like &lt;code&gt;Therapy&lt;/code&gt;, &lt;code&gt;Accounts&lt;/code&gt;, or &lt;code&gt;Billing&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;While domains might seem simple at first, they become much more powerful as our app grows.
That’s because many of Ash’s advanced features — like policies, code interfaces, and automated APIs — are built on top of domains.&lt;/p&gt;
&lt;p&gt;We’ll create a single &lt;code&gt;AshTherapy.Therapy&lt;/code&gt; domain, which looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule AshTherapy.Therapy do
  use Ash.Domain

  resources do
    resource AshTherapy.Therapy.User
    resource AshTherapy.Therapy.Conversation
    resource AshTherapy.Therapy.Message
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use the &lt;code&gt;resources&lt;/code&gt; DSL to wrap the individual resources managed by this Ash domain.&lt;/p&gt;
&lt;h2&gt;Understanding Ash Resources&lt;/h2&gt;
&lt;p&gt;An &lt;a href=&quot;https://hexdocs.pm/ash/dsl-ash-resource.html&quot;&gt;Ash resource&lt;/a&gt; represents a business entity — such as a &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Conversation&lt;/code&gt;, or &lt;code&gt;Message&lt;/code&gt; in our AshTherapy app.
Together with domains, resources form the business engine that powers our application.&lt;/p&gt;
&lt;p&gt;Every resource in Ash is just a normal Elixir module — until we add this line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;use Ash.Resource
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That one line turns a plain module into a powerful declarative resource.
It gives us access to Domain Specific Language (DSL) blocks like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;attributes&lt;/code&gt;: Define fields and data types&lt;/li&gt;
&lt;li&gt;&lt;code&gt;relationships&lt;/code&gt;: Define associations between resources&lt;/li&gt;
&lt;li&gt;&lt;code&gt;actions&lt;/code&gt;: Define what operations can be performed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are many other DSLs available, such as policies and identities, but in this post, we’ll focus on these three foundational blocks.&lt;/p&gt;
&lt;h3&gt;Resource Structure&lt;/h3&gt;
&lt;p&gt;Like Ash domains, resources are also plain Elixir modules that consume macros from the Ash library, which grant them their superpowers.
The basic structure of a resource looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule AshTherapy.Therapy.Message do
  use Ash.Resource,
    data_layer: AshPostgres.DataLayer

  postgres do
    # Database table and Repo configuration
  end

  attributes do
    # Resource attributes
  end

  relationships do
    # Resource associations
  end

  actions do
    # Resource actions
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, instead of showing full files for &lt;code&gt;Conversation&lt;/code&gt; and &lt;code&gt;Message&lt;/code&gt;, let’s highlight just the most interesting snippets from the AshTherapy project to understand each part.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Attributes&lt;/h3&gt;
&lt;p&gt;Here, we describe what information a conversation holds using the &lt;code&gt;attribute&lt;/code&gt; DSL. This might seem familiar to Ecto, where we use the &lt;code&gt;field&lt;/code&gt; macro. However, the &lt;code&gt;attribute&lt;/code&gt; macro is more powerful and offers a lot more options.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;attributes do
  uuid_primary_key :id

  attribute :goal, :string do
    allow_nil? false
    description &amp;quot;User’s goal or motive for starting this session.&amp;quot;
  end

  attribute :status, :atom do
    constraints one_of: [:active, :closed]
    default :active
    description &amp;quot;Lifecycle state of the session.&amp;quot;
  end

  attribute :started_at, :utc_datetime do
    default &amp;amp;DateTime.utc_now/0
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Declaring Relationships&lt;/h3&gt;
&lt;p&gt;Every conversation belongs to a user and contains messages.
That’s expressed like this in the &lt;code&gt;Conversation&lt;/code&gt; resource:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;relationships do
  belongs_to :user, AshTherapy.Therapy.User, allow_nil?: true
  has_many :messages, AshTherapy.Therapy.Message
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells Ash how our resources connect — it automatically handles loading, filtering, and association behaviors internally.&lt;/p&gt;
&lt;h3&gt;Declaring Business Actions&lt;/h3&gt;
&lt;p&gt;Now comes the heart of the resource: actions.
Actions tell Ash what operations can be performed — creation, updates, reads, etc.
Instead of writing explicit Elixir functions, we &lt;em&gt;configure&lt;/em&gt; behavior through macros.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;actions do
  defaults [:read]

  create :start_conversation do
    accept [:goal, :user_id]
    change set_attribute(:started_at, &amp;amp;DateTime.utc_now/0)
  end

  read :get_conversation_with_messages do
    argument :id, :uuid, allow_nil?: false
    filter expr(id == ^arg(:id))
    prepare build(load: [:messages])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s break down the &lt;code&gt;start_conversation&lt;/code&gt; action:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s a create action for the &lt;code&gt;Conversation&lt;/code&gt; resource.&lt;/li&gt;
&lt;li&gt;It accepts only two inputs — &lt;code&gt;goal&lt;/code&gt; and &lt;code&gt;user_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It automatically sets &lt;code&gt;started_at&lt;/code&gt; to the current time.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;status&lt;/code&gt; is already handled by its default value (&lt;code&gt;:active&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we compare this to a traditional Phoenix and Ecto setup, we’d have to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define a schema.&lt;/li&gt;
&lt;li&gt;Write a &lt;code&gt;changeset&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Write a function like &lt;code&gt;create_conversation&lt;/code&gt; inside a context.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;Repo.insert(changeset)&lt;/code&gt; manually.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With Ash, all of that is replaced by a simple, expressive declaration.&lt;/p&gt;
&lt;h3&gt;Reading Data with Built-in Preloading&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;get_conversation_with_messages&lt;/code&gt; action shows another elegant pattern:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fetch this conversation by ID and preload all related messages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;read :get_conversation_with_messages do
  argument :id, :uuid, allow_nil?: false
  filter expr(id == ^arg(:id))
  prepare build(load: [:messages])
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No need to define query joins or preload manually. Ash interprets the relationships we declared earlier and does the heavy lifting.&lt;/p&gt;
&lt;p&gt;In short:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We define &lt;strong&gt;what&lt;/strong&gt; our business entities look like.&lt;/li&gt;
&lt;li&gt;We describe &lt;strong&gt;how&lt;/strong&gt; they relate.&lt;/li&gt;
&lt;li&gt;We declare &lt;strong&gt;what&lt;/strong&gt; can be done with them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ash then turns those configurations into complete, consistent, and database-backed operations — no repetitive boilerplate required.&lt;/p&gt;
&lt;p&gt;Now that you’ve seen what Ash does at a high level, let’s take a deeper look at the philosophy that makes it so effective.&lt;/p&gt;
&lt;h2&gt;Declare Once, Derive the Rest&lt;/h2&gt;
&lt;p&gt;You might have heard the variation on Ash’s tagline:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Declare once, derive the rest.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is not just a catchy phrase — it captures the very heart of what makes Ash powerful.&lt;/p&gt;
&lt;p&gt;Let’s unpack that a bit.&lt;/p&gt;
&lt;p&gt;If we look at an &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Schema.html&quot;&gt;Ecto schema&lt;/a&gt;, it already feels declarative.
We describe the shape of our data, the fields, their types — and that’s a great starting point. Conceptually, Ecto begins in the right place: it encourages us to describe what data looks like instead of writing procedural code.&lt;/p&gt;
&lt;p&gt;But here’s where Ecto stops — and where Ash continues the journey.&lt;/p&gt;
&lt;p&gt;In Ecto, that declarative schema doesn’t get reused elsewhere.
After defining a schema, we still have to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write migrations manually, repeating much of the same information in SQL-like form.&lt;/li&gt;
&lt;li&gt;Write context functions that perform create, read, or update operations.&lt;/li&gt;
&lt;li&gt;Write controllers or APIs to expose those actions externally.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of that is work we do &lt;em&gt;again and again&lt;/em&gt; — even though the intent was already declared in the schema.&lt;/p&gt;
&lt;p&gt;Frameworks like Rails or Django solved this years ago by reusing their models to drive migrations, validations, and APIs automatically.
Ash brings that level of cohesion — and more — into the Elixir ecosystem.&lt;/p&gt;
&lt;p&gt;Here’s how Ash builds on Ecto’s declarative foundation and takes it several steps further:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Once a resource is defined, Ash can generate migrations automatically.
No need to manually write &lt;code&gt;create table(...)&lt;/code&gt; or update migrations when attributes change.
Even renames, removals, and relationship updates can be derived automatically.&lt;/li&gt;
&lt;li&gt;The same resource definition also powers API generation.
We can expose JSON:API, GraphQL, or RPC (like TypeScript remote procedure calls) in a single line of configuration — no need to write controllers or context functions.&lt;/li&gt;
&lt;li&gt;All of this information — attributes, actions, relationships — stays consistent across the system because it comes from one single source of truth: the resource definition itself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is what is meant by &lt;em&gt;“declare once, derive the rest”&lt;/em&gt;.
We define our &lt;strong&gt;business logic&lt;/strong&gt; in one place, and Ash intelligently derives everything else — migrations, APIs, validations, documentation — directly from that single declaration.&lt;/p&gt;
&lt;h2&gt;Quick Comparison: Ecto vs Ash&lt;/h2&gt;
&lt;p&gt;Here&amp;#39;s a quick look at Ecto and Ash&amp;#39;s features side-by-side:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Ecto&lt;/th&gt;
&lt;th&gt;Ash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;Schema Definition&lt;/td&gt;
&lt;td&gt;Declarative&lt;/td&gt;
&lt;td&gt;Declarative&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migrations&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Auto-generated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context Functions&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Derived from Actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Layer&lt;/td&gt;
&lt;td&gt;Handwritten&lt;/td&gt;
&lt;td&gt;Auto-generated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reuse&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;System-wide reuse&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Ash turns your domain model into the single source of truth across all layers.&lt;/p&gt;
&lt;h2&gt;Playing with Ash in IEx&lt;/h2&gt;
&lt;p&gt;Let’s now play with what we’ve built and see Ash in action.&lt;/p&gt;
&lt;p&gt;If you haven’t already cloned the repository, do it now and set up your project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/devcarrots/ash_therapy.git
cd ash_therapy
mix deps.get
mix ash.codegen
mix ash.migrate
iex -S mix
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Understanding &lt;code&gt;Ash.create&lt;/code&gt; and &lt;code&gt;Ash.read&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;So far, we have seen how to declare actions, but we haven&amp;#39;t executed them yet. Ash provides simple functions to interact with these resource actions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Ash.create/3&lt;/code&gt; (or &lt;code&gt;Ash.create!/3&lt;/code&gt;) executes a create action on a resource.
You provide the resource module, the action name, and the data map for that action.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ash.read/3&lt;/code&gt; (or &lt;code&gt;Ash.read!/3&lt;/code&gt;) executes a read action, usually returning filtered data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Create a User&lt;/h3&gt;
&lt;p&gt;Before we can start a conversation, we need a user.
I have already defined a &lt;code&gt;register_user&lt;/code&gt; action in our &lt;a href=&quot;https://github.com/devcarrots/ash_therapy/blob/main/lib/ash_therapy/therapy/user.ex#L14-L16&quot;&gt;User resource&lt;/a&gt;. It’s a simple create action that accepts a user’s name and stores a new record, similar in structure to the &lt;code&gt;start_conversation&lt;/code&gt; action we explored earlier.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; user =
  Ash.create!(
    AshTherapy.Therapy.User,
    :register_user,
    %{name: &amp;quot;Nisha&amp;quot;}
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This executes the &lt;code&gt;register_user&lt;/code&gt; action on the &lt;code&gt;User&lt;/code&gt; resource and stores a record in the database.
The returned struct includes an auto-generated UUID and timestamps.&lt;/p&gt;
&lt;h3&gt;Start a Conversation&lt;/h3&gt;
&lt;p&gt;Next, let’s start a conversation for this user.
A conversation needs a &lt;code&gt;goal&lt;/code&gt; (the user’s motive) and the &lt;code&gt;user_id&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; conversation =
  Ash.create!(
    AshTherapy.Therapy.Conversation,
    :start_conversation,
    %{goal: &amp;quot;I want to handle work stress&amp;quot;, user_id: user.id}
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This calls the &lt;code&gt;start_conversation&lt;/code&gt; action, automatically setting the &lt;code&gt;started_at&lt;/code&gt; timestamp. The &lt;code&gt;status&lt;/code&gt; defaults to &lt;code&gt;:active&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Send a Message&lt;/h3&gt;
&lt;p&gt;Now that we have a conversation set up, let’s send the first message.
I have defined a &lt;code&gt;send_message&lt;/code&gt; action in the &lt;a href=&quot;https://github.com/devcarrots/ash_therapy/blob/main/lib/ash_therapy/therapy/message.ex#L14-L17&quot;&gt;message resource&lt;/a&gt; to take care of that. It&amp;#39;s an action that can both send messages as a &lt;code&gt;:user&lt;/code&gt; and also as the &lt;code&gt;:ai&lt;/code&gt; agent (by setting the right &lt;code&gt;:role&lt;/code&gt; attribute), as shown below.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Ash.create!(
  AshTherapy.Therapy.Message,
  :send_message,
  %{
    content: &amp;quot;I feel anxious every Monday morning.&amp;quot;,
    conversation_id: conversation.id
    # The default value of attribute `:role` is `:user`. So the below line is not needed.
    # role: :user
  }
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;send_message&lt;/code&gt; action defaults the &lt;code&gt;role&lt;/code&gt; to &lt;code&gt;:user&lt;/code&gt;, sets the current timestamp, and saves the message.&lt;/p&gt;
&lt;p&gt;To simulate an AI reply, we can reuse the same action, but explicitly set the &lt;code&gt;role&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Ash.create!(
  AshTherapy.Therapy.Message,
  :send_message,
  %{
    content: &amp;quot;That sounds difficult. What usually triggers this feeling?&amp;quot;,
    conversation_id: conversation.id,
    # We set the `:role` to `:ai` when we want to override the default.
    role: :ai
  }
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This reuse of the same action demonstrates how defaults and configuration keep Ash concise and flexible.&lt;/p&gt;
&lt;h3&gt;Fetch the Conversation Messages&lt;/h3&gt;
&lt;p&gt;Now let’s see the conversation and all the messages.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Ash.read!(
  AshTherapy.Therapy.Conversation,
  :get_conversation_with_messages,
  %{id: conversation.id}
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;get_conversation_with_messages&lt;/code&gt; action loads the conversation and preloads all associated messages in one step.
You’ll see a neat struct showing the conversation goal, status, and a list of messages (both from the user and AI).&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Explored what Ash is and how it complements Phoenix&lt;/li&gt;
&lt;li&gt;Built three foundational resources: &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Conversation&lt;/code&gt;, and &lt;code&gt;Message&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Introduced attributes, relationships, and actions&lt;/li&gt;
&lt;li&gt;Learned how Ash embodies the principle “declare once, derive the rest”&lt;/li&gt;
&lt;li&gt;Tried out our domain interactively in IEx by calling Ash actions as if they were small, reusable business commands.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy Ash-ing! 👋&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>AppSignal’s Top 5 Elixir Posts in 2025</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/12/17/appsignals-top-5-elixir-posts-in-2025.html"/>
    <id>https://blog.appsignal.com/2025/12/17/appsignals-top-5-elixir-posts-in-2025.html</id>
    <published>2025-12-17T00:00:00+00:00</published>
    <updated>2025-12-17T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">It&#039;s time for our yearly rundown of our top 5 best-performing Elixir posts.</summary>
    <content type="html">&lt;p&gt;With the year wrapping up, we’re excited to reveal the five Elixir articles you read the most in 2025.&lt;/p&gt;
&lt;h2&gt;Top 5 Elixir Blog Posts in 2025 ⚗️&lt;/h2&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2025/02/04/building-a-distributed-rate-limiter-in-elixir-with-hashring.html&quot;&gt;Building a Distributed Rate Limiter in Elixir with HashRing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this post, we built a distributed rate limiter using HashRing for Elixir.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2025/03/18/getting-started-with-dialyzer-in-elixir.html&quot;&gt;Getting Started with Dialyzer in Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In part one of this two-part series, we explored the basics of Dialyzer.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2025/09/09/structs-and-embedded-schemas-in-elixir-beyond-maps.html&quot;&gt;Structs and Embedded Schemas in Elixir: Beyond Maps&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s dive into the ins and outs of structs and Ecto schemas.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2025/09/23/advanced-debugging-in-elixir-with-io-inspect.html&quot;&gt;Advanced Debugging in Elixir with IO.inspect&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Exploring both the fundamentals and advanced patterns for using IO.inspect effectively.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2025/10/07/batch-updates-and-advanced-inserts-in-ecto-for-elixir.html&quot;&gt;Batch Updates and Advanced Inserts in Ecto for Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this first part of a two-part series, we explored Ecto&amp;#39;s powerful batch update and advanced insert capabilities.&lt;/p&gt;
&lt;h2&gt;Season&amp;#39;s Greetings ❆ ⛄&lt;/h2&gt;
&lt;p&gt;Have a lovely holiday break. We&amp;#39;ll be back with more Elixir posts when the new year begins!&lt;/p&gt;
&lt;p&gt;If you haven’t already, don’t forget to &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter&lt;/a&gt;, so you never miss an upcoming post.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Build an Elixir App with Cowboy</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/11/25/build-an-elixir-app-with-cowboy.html"/>
    <id>https://blog.appsignal.com/2025/11/25/build-an-elixir-app-with-cowboy.html</id>
    <published>2025-11-25T00:00:00+00:00</published>
    <updated>2025-11-25T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s set up and use Cowboy, and design a simple pub/sub architecture.</summary>
    <content type="html">&lt;p&gt;Cowboy is a small, fast, and modern HTTP server for Erlang/OTP. It particularly shines when handling multiple concurrent connections with minimal overhead. This makes it a perfect choice for building lightweight, real-time streaming services.&lt;/p&gt;
&lt;p&gt;In this article, we’ll build a tiny real-time text pub/sub server using Cowboy. Our service supports HTTP-based publishing, allowing clients to subscribe using either WebSockets or Server-Sent Events (SSE). Think of it as a minimal message bus over the web, great for prototypes, internal dashboards, collaborative editors, or IoT telemetry applications.&lt;/p&gt;
&lt;p&gt;Not only will you learn how to set up and use Cowboy, but you’ll also gain insights into designing a simple yet effective pub/sub architecture. By the end of this article, you’ll have a solid foundation to build upon for more complex real-time applications.&lt;/p&gt;
&lt;h2&gt;Why Cowboy for Elixir?&lt;/h2&gt;
&lt;p&gt;Phoenix is the go-to web framework in Elixir, but sometimes you don’t need the full stack. Cowboy shines when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You want tight control over connections and protocols&lt;/li&gt;
&lt;li&gt;You’re building a focused service (e.g., streaming telemetry or real-time feeds)&lt;/li&gt;
&lt;li&gt;You want to avoid framework overhead and keep things lean&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cowboy’s design is close to the metal and as barebones as it gets. It doesn’t come with routing helpers or request processing pipelines—but that’s a feature, not a bug. You get raw access to HTTP and WebSocket layers, with no abstraction in your way. Perfect for protocol gateways, edge servers, or streaming APIs.&lt;/p&gt;
&lt;p&gt;In contrast, Phoenix is fantastic for full-featured web apps with rich templating, channels, and LiveView. However, if your application&amp;#39;s main responsibility is pushing data to clients with minimal latency, Cowboy’s simplicity can improve performance and reduce resource usage.&lt;/p&gt;
&lt;p&gt;As mentioned in the introduction, we will build a simple text pub/sub server that supports publishing and subscribing via HTTP, WebSockets, and Server-Sent Events (SSE), which is a great fit for Cowboy’s strengths.&lt;/p&gt;
&lt;h2&gt;Project Setup and Bootstrapping Cowboy&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s get started by creating a new Mix project and adding Cowboy as a dependency.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix new text_bus --sup
cd text_bus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a new Elixir project with a supervision tree. Next, open &lt;code&gt;mix.exs&lt;/code&gt; and add Cowboy and Jason (for JSON encoding) to the dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
 [
 {:cowboy, &amp;quot;~&amp;gt; 2.10&amp;quot;},
 {:jason, &amp;quot;~&amp;gt; 1.4&amp;quot;}
 ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fetch the dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With our dependencies in place, we can set up Cowboy to start an HTTP listener on port 4000. The first step is to create a module to start the Cowboy server. Create a new file at &lt;code&gt;lib/text_bus/http_server.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.HTTPServer do
  use GenServer

  def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)

  def init(_opts) do
    dispatch =
      :cowboy_router.compile([
 {:_, [
 {&amp;quot;/health&amp;quot;, TextBus.Handlers.Health, []}
 ]}
 ])

 {:ok, _} =
      :cowboy.start_clear(
        :http,
 [port: 4000],
 %{env: %{dispatch: dispatch}}
 )

 {:ok, %{}}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this code might look a bit complex, here’s a breakdown:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We define a &lt;code&gt;TextBus.HTTPServer&lt;/code&gt; module that uses &lt;code&gt;GenServer&lt;/code&gt; to manage the Cowboy server lifecycle.&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;init/1&lt;/code&gt; function, we set up a simple router with a health check endpoint at &lt;code&gt;/health&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We start the Cowboy server on port 4000, passing in our routing configuration.&lt;/li&gt;
&lt;li&gt;Finally, we return the initial server state, an empty map.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, we need to make sure the application starts the Cowboy server. Open &lt;code&gt;lib/text_bus/application.ex&lt;/code&gt; and modify the &lt;code&gt;start/2&lt;/code&gt; function to include our &lt;code&gt;TextBus.HTTPServer&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Application do
  use Application

  def start(_type, _args) do
    children = [
      TextBus.HTTPServer
 ]

    Supervisor.start_link(children, strategy: :one_for_one, name: TextBus.Supervisor)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s create the health check handler in &lt;code&gt;lib/text_bus/handlers/health.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Handlers.Health do
  @behaviour :cowboy_handler

  def init(req, state) do
 {:ok, req} =
      :cowboy_req.reply(200, %{&amp;quot;content-type&amp;quot; =&amp;gt; &amp;quot;text/plain&amp;quot;}, &amp;quot;OK&amp;quot;, req)

 {:ok, req, state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This handler returns a 200 OK response with the text &amp;quot;OK&amp;quot; as our health check. We can make sure our Cowboy scaffold is working by starting the application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix run --no-halt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then using &lt;code&gt;curl&lt;/code&gt; to hit the health endpoint:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -i http://localhost:4000/health
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If everything is set up correctly, you should see a 200 OK response with the text &amp;quot;OK&amp;quot;. Something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;❯ curl -i http://localhost:4000/health
HTTP/1.1 200 OK
content-length: 2
content-type: text/plain
date: Thu, 18 Sep 2025 13:08:21 GMT
server: Cowboy

OK⏎
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we start the implementation, let&amp;#39;s quickly outline what a pub/sub server does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clients can publish messages to a topic via HTTP POST requests.&lt;/li&gt;
&lt;li&gt;Clients can subscribe to topics via WebSockets or Server-Sent Events (SSE) to receive real-time updates.&lt;/li&gt;
&lt;li&gt;The server maintains a buffer of recent messages for each topic to allow new subscribers to catch up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, let&amp;#39;s move on to the implementation.&lt;/p&gt;
&lt;h2&gt;Topic Model, Publish Flow, and Subscriptions&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s define a &lt;code&gt;Topic&lt;/code&gt; module to manage individual topics. Each topic will be a GenServer that maintains a ring buffer of messages and tracks subscribers. Create a new file at &lt;code&gt;lib/text_bus/topic.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Topic do
  use GenServer

  @buffer_size 100

  # Client API
  def start_link(name), do: GenServer.start_link(__MODULE__, name, name: via(name))
  def publish(topic, msg), do: GenServer.cast(via(topic), {:publish, msg})
  def subscribe(topic, pid), do: GenServer.cast(via(topic), {:subscribe, pid})
  def unsubscribe(topic, pid), do: GenServer.cast(via(topic), {:unsubscribe, pid})
  def replay(topic, n), do: GenServer.call(via(topic), {:replay, n})

  defp via(name), do: {:via, Registry, {TextBus.TopicRegistry, name}}

  ## Server

  def init(name) do
    # Unnamed table: first arg can be any atom; result is a tid we keep in state.
    table = :ets.new(:topic_messages, [:ordered_set, :protected])
 {:ok, %{name: name, seq: 0, table: table, subs: MapSet.new()}}
  end

  def handle_cast({:publish, msg}, state) do
    seq = state.seq + 1
    :ets.insert(state.table, {seq, msg})
    Enum.each(state.subs, fn pid -&amp;gt; send(pid, {:message, state.name, seq, msg}) end)
 {:noreply, %{state | seq: seq}}
  end

  def handle_cast({:subscribe, pid}, state),
    do: {:noreply, %{state | subs: MapSet.put(state.subs, pid)}}

  def handle_cast({:unsubscribe, pid}, state),
    do: {:noreply, %{state | subs: MapSet.delete(state.subs, pid)}}

  def handle_call({:replay, n}, _from, state) do
    msgs =
      :ets.tab2list(state.table)
      |&amp;gt; Enum.sort_by(&amp;amp;elem(&amp;amp;1, 0))
      |&amp;gt; Enum.take(-n)

 {:reply, msgs, state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;This &lt;code&gt;Topic&lt;/code&gt; module does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It uses &lt;code&gt;GenServer&lt;/code&gt; to manage the state of each topic.&lt;/li&gt;
&lt;li&gt;It maintains an ETS table as a ring buffer to store messages, allowing efficient storage and retrieval.&lt;/li&gt;
&lt;li&gt;It tracks subscribers using a &lt;code&gt;MapSet&lt;/code&gt; to avoid duplicates.&lt;/li&gt;
&lt;li&gt;It provides functions to publish messages, subscribe/unsubscribe clients, and replay recent messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will also need to set up a registry for our topics. Create a new file at &lt;code&gt;lib/text_bus/topic_sup.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.TopicSup do
  use DynamicSupervisor

  def start_link(_), do: DynamicSupervisor.start_link(__MODULE__, :ok, name: __MODULE__)

  def init(:ok), do: DynamicSupervisor.init(strategy: :one_for_one)

  def start_topic(name) do
    child_spec = {TextBus.Topic, name}
    DynamicSupervisor.start_child(__MODULE__, child_spec)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&amp;#39;s add a registry and the topic supervisor to our application supervision tree. Update &lt;code&gt;lib/text_bus/application.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Application do
  use Application

  def start(_type, _args) do
    children = [
 {Registry, keys: :unique, name: TextBus.TopicRegistry},
      TextBus.TopicSup,
      TextBus.HTTPServer
 ]

    Supervisor.start_link(children, strategy: :one_for_one, name: TextBus.Supervisor)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;{Registry, keys: :unique, name: TextBus.TopicRegistry},&lt;/code&gt; line sets up an in-memory registry to keep track of our topics. Keep in mind that this is just for our tutorial; in production, you will want to use something with more persistence.&lt;/p&gt;
&lt;p&gt;Now that we have a working topic model, we can implement the publish endpoint. Create a new handler at &lt;code&gt;lib/text_bus/handlers/publish.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Handlers.Publish do
  @behaviour :cowboy_handler

  def init(req, state) do
    topic = :cowboy_req.binding(:topic, req)
 {:ok, body, req} = :cowboy_req.read_body(req)

    case Jason.decode(body) do
 {:ok, %{&amp;quot;message&amp;quot; =&amp;gt; msg}} -&amp;gt;
        ensure_topic(topic)
        TextBus.Topic.publish(topic, msg)

        req =
          :cowboy_req.stream_reply(202, %{&amp;quot;content-type&amp;quot; =&amp;gt; &amp;quot;application/json&amp;quot;}, req)

        :ok = :cowboy_req.stream_body(~s({&amp;quot;status&amp;quot;:&amp;quot;accepted&amp;quot;}), :fin, req)
 {:ok, req, state}

      _ -&amp;gt;
 {:ok, req} = :cowboy_req.reply(400, %{}, &amp;quot;invalid&amp;quot;, req)
 {:ok, req, state}
    end
  end

  defp ensure_topic(name) do
    case Registry.lookup(TextBus.TopicRegistry, name) do
 [] -&amp;gt; TextBus.TopicSup.start_topic(name)
      _ -&amp;gt; :ok
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, add the publish route to our Cowboy router in &lt;code&gt;lib/text_bus/http_server.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;dispatch = :cowboy_router.compile([
 {:_, [
 {&amp;quot;/health&amp;quot;, TextBus.Handlers.Health, []},
 {&amp;quot;/publish/:topic&amp;quot;, TextBus.Handlers.Publish, []},
 ]}
])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next component is the SSE endpoint. This endpoint allows clients to subscribe to topics and receive real-time updates. SSE is dead simple: send &lt;code&gt;&amp;quot;content-type&amp;quot; =&amp;gt; &amp;quot;text/event-stream&amp;quot;&lt;/code&gt;, keep the connection open, and push lines like &lt;code&gt;data: hello&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Create a new handler at &lt;code&gt;lib/text_bus/handlers/sse.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Handlers.SSE do
  @behaviour :cowboy_handler

  def init(req, state) do
    topic = :cowboy_req.binding(:topic, req)
    ensure_topic(topic)

    TextBus.Topic.subscribe(topic, self())

    req =
      :cowboy_req.stream_reply(200, %{
        &amp;quot;content-type&amp;quot; =&amp;gt; &amp;quot;text/event-stream&amp;quot;,
        &amp;quot;cache-control&amp;quot; =&amp;gt; &amp;quot;no-cache&amp;quot;,
        &amp;quot;connection&amp;quot; =&amp;gt; &amp;quot;keep-alive&amp;quot;
 }, req)

    loop(req, topic)
 {:ok, req, state}
  end

  defp loop(req, topic) do
    receive do
 {:message, ^topic, seq, msg} -&amp;gt;
        frame = &amp;quot;id: #{seq}\ndata: #{msg}\n\n&amp;quot;
        :ok = :cowboy_req.stream_body(frame, :nofin, req)
        loop(req, topic)

 {:cowboy_req, :terminate} -&amp;gt;
        TextBus.Topic.unsubscribe(topic, self())
        :ok
    end
  end

  defp ensure_topic(name) do
    case Registry.lookup(TextBus.TopicRegistry, name) do
 [] -&amp;gt; TextBus.TopicSup.start_topic(name)
      _ -&amp;gt; :ok
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our next handler will be for WebSocket subscriptions. WebSockets provide a full-duplex communication channel over a single TCP connection, making them ideal for real-time applications.&lt;/p&gt;
&lt;p&gt;Create a new handler at &lt;code&gt;lib/text_bus/handlers/websocket.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Handlers.WS do
  @behaviour :cowboy_websocket

  def init(req, state) do
    topic = :cowboy_req.binding(:topic, req)
    ensure_topic(topic)
 {:cowboy_websocket, req, %{topic: topic}}
  end

  def websocket_init(state) do
    TextBus.Topic.subscribe(state.topic, self())
 {:ok, state}
  end

  def websocket_handle({:text, msg}, state) do
    TextBus.Topic.publish(state.topic, msg)
 {:ok, state}
  end

  def websocket_info({:message, _topic, seq, msg}, state) do
 {:reply, {:text, Jason.encode!(%{id: seq, data: msg})}, state}
  end

  def terminate(_reason, _req, state) do
    TextBus.Topic.unsubscribe(state.topic, self())
    :ok
  end

  defp ensure_topic(name) do
    case Registry.lookup(TextBus.TopicRegistry, name) do
 [] -&amp;gt; TextBus.TopicSup.start_topic(name)
      _ -&amp;gt; :ok
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, add the WebSocket route to our Cowboy router in &lt;code&gt;lib/text_bus/http_server.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;dispatch = :cowboy_router.compile([
 {:_, [
 {&amp;quot;/health&amp;quot;, TextBus.Handlers.Health, []},
 {&amp;quot;/publish/:topic&amp;quot;, TextBus.Handlers.Publish, []},
 {&amp;quot;/sse/:topic&amp;quot;, TextBus.Handlers.SSE, []},
 {&amp;quot;/ws/:topic&amp;quot;, TextBus.Handlers.WS, []}
 ]}
])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s test our progress so far by starting the application again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix run --no-halt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start by subscribing to a topic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -N http://localhost:4000/sse/demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then in another terminal, using &lt;code&gt;curl&lt;/code&gt; to publish a message:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -X POST -d &amp;#39;{&amp;quot;message&amp;quot;:&amp;quot;Hello, World!&amp;quot;}&amp;#39; http://localhost:4000/publish/demo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If everything is working correctly, you should see the message appear in the SSE subscriber terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -N http://localhost:4000/sse/demo
id: 1
data: Hello, World!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Replay, Stats, and Testing&lt;/h2&gt;
&lt;p&gt;Alright, although we technically have a working pub/sub server, it&amp;#39;s only fully real-time. This means that if you are connected when a message is published, you will receive it. If you connect after a message is published, though, you will miss it. To solve this, we will add a replay endpoint that allows clients to request the last N messages for a topic.&lt;/p&gt;
&lt;p&gt;Previously, we ensured that messages were stored in ETS (see &lt;code&gt;TextBus.Topic&lt;/code&gt;). Now we will create a new handler to expose a replay endpoint. Create a new file at &lt;code&gt;lib/text_bus/handlers/replay.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Handlers.Replay do
  @behaviour :cowboy_handler

  def init(req, state) do
    topic = :cowboy_req.binding(:topic, req)
    n = parse_n(:cowboy_req.qs_val(&amp;quot;n&amp;quot;, req, &amp;quot;10&amp;quot;))

    msgs =
      case Registry.lookup(TextBus.TopicRegistry, topic) do
 [] -&amp;gt; []
        _ -&amp;gt; TextBus.Topic.replay(topic, n)
      end

    body = Jason.encode!(Enum.map(msgs, fn {id, msg} -&amp;gt; %{id: id, data: msg} end))
 {:ok, req} = :cowboy_req.reply(200, %{&amp;quot;content-type&amp;quot; =&amp;gt; &amp;quot;application/json&amp;quot;}, body, req)
 {:ok, req, state}
  end

  defp parse_n(val) do
    case Integer.parse(val) do
 {n, _} when n &amp;gt; 0 -&amp;gt; n
      _ -&amp;gt; 10
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don&amp;#39;t forget to add the replay route to our Cowboy router in &lt;code&gt;lib/text_bus/http_server.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{&amp;quot;/replay/:topic&amp;quot;, TextBus.Handlers.Replay, []}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Like we did before, we can test our progress so far by starting the application again and using &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Start SSE subscription
curl -N http://localhost:4000/sse/demo

# In another shell, publish a few messages
curl -XPOST http://localhost:4000/publish/demo \
 -H &amp;quot;content-type: application/json&amp;quot; \
  -d &amp;#39;{&amp;quot;message&amp;quot;:&amp;quot;hello&amp;quot;}&amp;#39;

curl -XPOST http://localhost:4000/publish/demo \
 -H &amp;quot;content-type: application/json&amp;quot; \
  -d &amp;#39;{&amp;quot;message&amp;quot;:&amp;quot;world&amp;quot;}&amp;#39;

# Replay last 2 messages
curl &amp;quot;http://localhost:4000/replay/demo?n=2&amp;quot;
# =&amp;gt; [{&amp;quot;id&amp;quot;:1,&amp;quot;data&amp;quot;:&amp;quot;hello&amp;quot;},{&amp;quot;id&amp;quot;:2,&amp;quot;data&amp;quot;:&amp;quot;world&amp;quot;}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next and final component that we will add is a stats endpoint. This endpoint will provide some basic introspection into our server, such as the number of topics, subscribers, and messages in buffers. Create a new handler at &lt;code&gt;lib/text_bus/handlers/stats.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TextBus.Handlers.Stats do
  @behaviour :cowboy_handler

  def init(req, state) do
    topics =
      Registry.select(TextBus.TopicRegistry, [{{:&amp;quot;$1&amp;quot;, :_, :_}, [], [:&amp;quot;$1&amp;quot;]}])

 stats =
  Enum.map(topics, fn topic -&amp;gt;
        [{pid, _}] = Registry.lookup(TextBus.TopicRegistry, topic)
 %{topic: topic, subscribers: subscriber_count(pid)}
 end)

 body = Jason.encode!(%{topics: stats, total_topics: length(stats)})
 {:ok, req} = :cowboy_req.reply(200, %{&amp;quot;content-type&amp;quot; =&amp;gt; &amp;quot;application/json&amp;quot;}, body, req)
 {:ok, req, state}
 end

 defp subscriber_count(pid) do
 # Reach into process state (simplest for demo purposes)
 case :sys.get_state(pid) do
 %{subs: subs} -&amp;gt; MapSet.size(subs)
 _ -&amp;gt; 0
 end
 end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s add the stats route to our Cowboy router in &lt;code&gt;lib/text_bus/http_server.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{&amp;quot;/stats&amp;quot;, TextBus.Handlers.Stats, []}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s test our progress so far by starting the application again and using &lt;code&gt;curl&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Start SSE subscription
curl -N http://localhost:4000/sse/demo

# In another shell, publish a few messages
curl -XPOST http://localhost:4000/publish/demo \
 -H &amp;quot;content-type: application/json&amp;quot; \
  -d &amp;#39;{&amp;quot;message&amp;quot;:&amp;quot;hello&amp;quot;}&amp;#39;

curl -XPOST http://localhost:4000/publish/demo \
 -H &amp;quot;content-type: application/json&amp;quot; \
  -d &amp;#39;{&amp;quot;message&amp;quot;:&amp;quot;world&amp;quot;}&amp;#39;

# Replay last 2 messages
curl &amp;quot;http://localhost:4000/replay/demo?n=2&amp;quot;
# =&amp;gt; [{&amp;quot;id&amp;quot;:1,&amp;quot;data&amp;quot;:&amp;quot;hello&amp;quot;},{&amp;quot;id&amp;quot;:2,&amp;quot;data&amp;quot;:&amp;quot;world&amp;quot;}]

# Stats endpoint
curl http://localhost:4000/stats
# =&amp;gt; {&amp;quot;status&amp;quot;:&amp;quot;accepted&amp;quot;}{&amp;quot;status&amp;quot;:&amp;quot;accepted&amp;quot;}[{&amp;quot;data&amp;quot;:&amp;quot;hello&amp;quot;,&amp;quot;id&amp;quot;:1},{&amp;quot;data&amp;quot;:&amp;quot;world&amp;quot;,&amp;quot;id&amp;quot;:2}]{&amp;quot;topics&amp;quot;:[{&amp;quot;topic&amp;quot;:&amp;quot;demo&amp;quot;,&amp;quot;subscribers&amp;quot;:1}],&amp;quot;total_topics&amp;quot;:1}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;When to Use Cowboy vs. Phoenix for Elixir&lt;/h2&gt;
&lt;p&gt;At this point, we have a basic but fully functional pub/sub server built with Cowboy. You may wonder when to choose Cowboy over Phoenix for your projects.&lt;/p&gt;
&lt;p&gt;Cowboy vs. Phoenix is not an either/or decision. They serve different purposes:&lt;/p&gt;
&lt;h3&gt;Cowboy Shines When…&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You need full control over the protocol.&lt;/strong&gt; Cowboy gives you raw access to HTTP, WebSockets, and even HTTP/2 without any framework abstractions in your way.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You’re building focused services.&lt;/strong&gt; Things like telemetry pipelines, IoT data ingestion services, internal dashboards, or custom protocol gateways often just need a way to push data around quickly, not templating engines or an ORM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You want to minimize overhead.&lt;/strong&gt; Cowboy itself is small. No view layers, no router DSL, no middleware stack. That means fewer moving parts, less memory, and less latency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You care about lightweight deployment.&lt;/strong&gt; For sidecars, edge servers, or single-purpose services, starting from Cowboy keeps the footprint minimal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Phoenix Makes More Sense When…&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You’re building a full web application.&lt;/strong&gt; If you need HTML templates, session management, static file serving, and a router DSL, Phoenix saves you a mountain of boilerplate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need higher-level abstractions.&lt;/strong&gt; Phoenix Channels, Presence, and LiveView remove the need to roll your own pub/sub, replay, and state management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You’re working in a team.&lt;/strong&gt; Phoenix has a common structure, clear conventions, and rich documentation, which makes onboarding new developers easier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You need built-in scaling tools.&lt;/strong&gt; Phoenix PubSub is cluster-aware out of the box, so you don’t have to hand-roll distributed registries or message propagation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nothing illustrates this point better than the fact that Phoenix uses Cowboy under the hood. Here is how that works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cowboy is the HTTP/WebSocket server.&lt;/strong&gt; It handles sockets, parses requests, and manages connections.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plug is a middleware abstraction&lt;/strong&gt; (think “Rack” in Ruby or “Express” in Node). It defines a standard way to build request/response pipelines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Phoenix builds on Plug&lt;/strong&gt;, adding routing, controllers, views, channels, LiveView, etc. Plug itself runs inside Cowboy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having a better understanding of Cowboy’s strengths will serve you well if you are working on the Elixir ecosystem. Plenty of production systems use Cowboy under the hood, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RabbitMQ management &amp;amp; Web STOMP plugin&lt;/strong&gt; – RabbitMQ (written in Erlang) uses Cowboy for its HTTP APIs, the management console, and WebSocket/STOMP support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elixir Language Server (ElixirLS)&lt;/strong&gt; – the LSP server for editors like VS Code runs Cowboy directly to expose JSON-RPC endpoints over HTTP.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VerneMQ&lt;/strong&gt; – a high-performance MQTT broker built in Erlang; its HTTP status and plugin endpoints are served through Cowboy.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;To recap, we built a lightweight real-time pub/sub server directly on top of Cowboy. Along the way, you learned how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set up &lt;strong&gt;Cowboy&lt;/strong&gt; as a supervised OTP process and wire it into a simple Elixir app.&lt;/li&gt;
&lt;li&gt;Define custom handlers for HTTP, SSE, and WebSocket endpoints.&lt;/li&gt;
&lt;li&gt;Model topics as processes with an ETS-backed buffer for replay.&lt;/li&gt;
&lt;li&gt;Expose introspection endpoints like &lt;code&gt;/replay&lt;/code&gt; and &lt;code&gt;/stats&lt;/code&gt; for debugging and observability.&lt;/li&gt;
&lt;li&gt;Test the system end-to-end using &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;wscat&lt;/code&gt;, and a browser-based SSE client.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result is a minimal but functional message bus: publishers post messages to a topic, subscribers receive them instantly, and operators can replay history or check system health. It’s a great foundation for prototypes, internal dashboards, IoT telemetry, or anywhere you need real-time streaming without the weight of a full framework.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Debugging in Elixir with Observer</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/11/04/debugging-in-elixir-with-observer.html"/>
    <id>https://blog.appsignal.com/2025/11/04/debugging-in-elixir-with-observer.html</id>
    <published>2025-11-04T00:00:00+00:00</published>
    <updated>2025-11-04T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s learn how to access Erlang&#039;s Observer GUI and debug an Elixir project that leaks memory.</summary>
    <content type="html">&lt;p&gt;Erlang&amp;#39;s Observer is often discussed in passing and regarded as a curiosity during Elixir courses. However, Observer provides many powerful tools for monitoring and debugging your application, both in development and production.&lt;/p&gt;
&lt;p&gt;Together, we will learn how to access the Observer GUI and debug a project that leaks memory, both locally and through a remote node. We will set up process tracing and track garbage collections to find the offending code in our sample project.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Set Up: Verifying Observer in Your Elixir Installation&lt;/h2&gt;
&lt;p&gt;Start by opening an IEx session:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now try to start the Observer GUI:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex&amp;gt; :observer.start()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The return value &lt;code&gt;:ok&lt;/code&gt; should appear and a new window should open.&lt;/p&gt;
&lt;p&gt;If you get an error message about a missing &lt;code&gt;:observer&lt;/code&gt; module, your Erlang installation might have been compiled without the &lt;code&gt;:observer&lt;/code&gt; or &lt;code&gt;:wx&lt;/code&gt; modules, or WxWidgets might be missing from your system. Refer to the instructions of your toolchain manager of choice to follow along.&lt;/p&gt;
&lt;h2&gt;The Observer GUI in Erlang for Elixir&lt;/h2&gt;
&lt;p&gt;The GUI has 9 separate tabs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;System&lt;/strong&gt; shows an overview of your system&amp;#39;s capabilities, memory and CPU usage, and runtime statistics.
&lt;img src=&quot;/images/blog/2025-11/observer_00.png&quot; alt=&quot;The Observer GUI showing the System tab&quot;/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load Charts&lt;/strong&gt; displays live memory, scheduler utilization, and I/O statistics.
&lt;img src=&quot;/images/blog/2025-11/observer_01.png&quot; alt=&quot;The Observer GUI showing the Load Charts tab&quot;/&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Allocators&lt;/strong&gt; shows the Erlang runtime&amp;#39;s memory carriers usage.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/observer_02.png&quot; alt=&quot;The Observer GUI showing the Memory Allocators tab&quot;/&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Applications&lt;/strong&gt; shows the different running applications and their processes&amp;#39; supervision trees.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/observer_03.png&quot; alt=&quot;The Observer GUI showing the Applications tab&quot;/&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Processes&lt;/strong&gt; lists processes, the number of reductions, memory usage, and mailbox sizes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/observer_04.png&quot; alt=&quot;The Observer GUI showing the Processes tab&quot;/&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ports&lt;/strong&gt; and &lt;strong&gt;Sockets&lt;/strong&gt;, respectively, list open Erlang ports and sockets and their owner processes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Table Viewer&lt;/strong&gt; tab lists viewable ETS tables. You can use the &lt;code&gt;View &amp;gt; View Unreadable Tables&lt;/code&gt; OS menu to show more tables than the default state displays.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/observer_05.png&quot; alt=&quot;The Observer GUI showing the Table Viewer tab&quot;/&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Trace Overview&lt;/strong&gt;, where we can set up tracing and view traces for offending processes, which we will use extensively in the next steps of this article.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, if you have already used the Phoenix Framework and the LiveDashboard package, you might notice that there is some intersection between what Observer and LiveDashboard provide. However, LiveDashboard is more tailored to monitoring web applications.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/live_dashboard.png&quot; alt=&quot;LiveDashboard&amp;#39;s main UI&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I encourage you to check out these various tools before continuing. As an example, try selecting applications to see their supervision tree, or inspect the contents of ETS tables.&lt;/p&gt;
&lt;p&gt;We will now proceed to set up a project with a faulty process and debug it using Observer.&lt;/p&gt;
&lt;h2&gt;Project Setup: Elixir App with Leaking Memory&lt;/h2&gt;
&lt;p&gt;We will create a simple Elixir application with a process that periodically leaks memory. This problem can occur in real applications if multiple processes get hold of large binaries, because the runtime shares large binaries stored in a dedicated heap instead of copying them.&lt;/p&gt;
&lt;h3&gt;Creating the Project&lt;/h3&gt;
&lt;p&gt;In your terminal, create the project with Mix, including a supervision tree, and change directory to this new folder:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix new demo_app --sup
cd demo_app
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Add the Offending Process Module&lt;/h3&gt;
&lt;p&gt;Create a new &lt;code&gt;lib/demo_app/offending_process.ex&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule DemoApp.OffendingProcess do
  use GenServer
  require Logger

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  def init(_opts) do
    schedule_work()
    {:ok, %{binaries: []}}
  end

  def handle_info(:work, state) do
    large_binary = :crypto.strong_rand_bytes(512_000)

    new_state = %{state | binaries: [large_binary | state.binaries]}

    IO.puts(&amp;quot;OffendingProcess created binary.&amp;quot;)

    schedule_work()

    {:noreply, new_state}
  end

  defp schedule_work do
    Process.send_after(self(), :work, 2_000)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Update the Application Supervisor&lt;/h3&gt;
&lt;p&gt;Edit &lt;code&gt;lib/demo_app/application.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule DemoApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Add the OffendingProcess to the supervision tree
      DemoApp.OffendingProcess
    ]

    opts = [strategy: :one_for_one, name: DemoApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Add the Observer Backend&lt;/h3&gt;
&lt;p&gt;Edit &lt;code&gt;mix.exs&lt;/code&gt; to add the &lt;code&gt;:runtime_tools&lt;/code&gt; application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def application do
  [
    extra_applications: [:logger, :runtime_tools],
    mod: {DemoApp.Application, []}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s start the application in IEx with a named node, so we can connect to it from another node running Observer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex --name demo@127.0.0.1 --cookie democookie -S mix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see messages printed every 2 seconds.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;OffendingProcess created binary.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Connecting Observer from a Separate Node&lt;/h3&gt;
&lt;p&gt;In a new terminal, start a second hidden IEx node.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex --hidden --name observer@127.0.0.1 --cookie democookie
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in the IEx session, connect to the first node and start Observer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex&amp;gt; Node.connect(:&amp;quot;demo@127.0.0.1&amp;quot;)
true
iex&amp;gt; :observer.start(:&amp;quot;demo@127.0.0.1&amp;quot;)
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you navigate to the Processes tab, you should see the &lt;code&gt;OffendingProcess&lt;/code&gt;&amp;#39;s memory usage slowly increase as the number of references to large binaries it holds grows.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/observer_window_remote_node.png&quot; alt=&quot;Observer window remote node&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the System tab, you can see overall memory usage and binary-specific memory usage increase more quickly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/observer_window_remote_node_2.png&quot; alt=&quot;System tab in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;This two-node setup means we can avoid interfering with resource usage measurements on the first node, by not running the Observer app directly on it.&lt;/p&gt;
&lt;h2&gt;Debugging a Remote System with Observer&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s set up tracing for our offending process from the Observer GUI controlled by our hidden node. Go to the Processes tab, right-click on &lt;code&gt;Elixir.DemoApp.OffendingProcess&lt;/code&gt;, and select &amp;quot;Trace selected processes&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/select_a_process.png&quot; alt=&quot;Select a process&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the process options, select the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trace function call&lt;/li&gt;
&lt;li&gt;Trace arity instead of arguments&lt;/li&gt;
&lt;li&gt;Trace garbage collections&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/process_options.png&quot; alt=&quot;Process options in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Move to the Trace Overview tab and click on the process now listed in the rightmost part of the GUI.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/select_process_in_trace.png&quot; alt=&quot;Select a process in a trace in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Click on the &amp;quot;Add Trace Pattern&amp;quot; button at the bottom of the GUI. In the pop-up that opens, select the module that we are looking to trace: &lt;code&gt;Elixir.DemoApp.OffendingProcess&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/select_module.png&quot; alt=&quot;Select module in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the second pop-up that opens, select functions to trace. We will select &lt;code&gt;schedule_work/0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/select_functions.png&quot; alt=&quot;Select functions in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The next pop-up asks us to select or write a Match Specification for our traces. If you are already familiar with &lt;code&gt;:ets&lt;/code&gt; (the Erlang Term Storage application), the match specifications used to perform queries with &lt;code&gt;:ets.select/2&lt;/code&gt; are the same concept, despite having a slightly different grammar. Match specifications are detailed in the documentation of the Erlang Runtime System Application (ERTS).&lt;/p&gt;
&lt;p&gt;For our purpose, we will select the pre-existing &amp;quot;Return Trace&amp;quot; match specification. Here, the &lt;code&gt;return_trace&lt;/code&gt; function causes a &lt;code&gt;return_from&lt;/code&gt; trace message to be sent when the selected function returns.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/select_return_traces.png&quot; alt=&quot;Select return trace in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the leftmost part of the window, click on &amp;quot;Start Trace&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/start_trace.png&quot; alt=&quot;Start trace in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;A window will open where each &lt;code&gt;schedule_work/0&lt;/code&gt; call will log the entry and return from that function.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/trace_00.png&quot; alt=&quot;Log entry and return in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;After a while, you will notice a different log: minor garbage collections triggered by the VM. In short, a garbage collection is an attempt to free memory by deleting data that cannot be referenced anymore.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-11/trace_01.png&quot; alt=&quot;Garbage collections in Observer&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the screenshot, we can read information about the garbage collection that just occurred. All sizes are expressed in words.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;old_heap_block_size&lt;/code&gt; is the size of the memory block storing the heap pre-collection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;heap_block_size&lt;/code&gt; is the size of the memory block storing both the heap and the stack&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mbuf_size&lt;/code&gt; is the size of the process&amp;#39;s message buffers&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recent_size&lt;/code&gt; is the size of the data that passed the previous garbage collection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stack_size&lt;/code&gt; is the size of the stack&lt;/li&gt;
&lt;li&gt;&lt;code&gt;old_heap_size&lt;/code&gt; is the size of block heap actually used, pre-collection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;heap_size&lt;/code&gt; is the size of block heap actually used&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bin_vheap_size&lt;/code&gt; is the size of binaries referenced from the process heap&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bin_vheap_block_size&lt;/code&gt; is the size of binaries allowed in the process&amp;#39;s virtual heap before triggering a garbage collection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key that interests us the most here is &lt;code&gt;bin_vheap_size&lt;/code&gt;, describing the space taken by binaries referenced in the process. We are talking about a &lt;em&gt;virtual heap&lt;/em&gt; here because large binaries aren&amp;#39;t actually stored in the process&amp;#39;s heap, but in a special and global binary heap as an optimization. In writing this article, when I first started tracing, this key read 7_168_092 words. After a while, it grew to 44_096_000 words.&lt;/p&gt;
&lt;p&gt;Indeed, going back to the &amp;quot;System&amp;quot; tab in the Observer GUI, I can see 372MiB taken by the binaries.&lt;/p&gt;
&lt;p&gt;And this concludes our overview of the Observer GUI!&lt;/p&gt;
&lt;h2&gt;Going Further&lt;/h2&gt;
&lt;p&gt;As you can see, the Observer GUI&amp;#39;s capabilities are quite extensive and it is difficult to provide an exhaustive tour here.&lt;/p&gt;
&lt;p&gt;Here are a few things you can try yourself to dive a bit deeper:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find the supervision tree of an application in the &amp;quot;Applications&amp;quot; tab, see its supervision strategies, and terminate a few of its children&lt;/li&gt;
&lt;li&gt;Inspect the state of a long-running process. Can you see all of its internal state in your IEx session?&lt;/li&gt;
&lt;li&gt;Trace specific functions through your application, then try to trace them without Observer, with &lt;code&gt;:erlang.trace/3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Try to start &lt;code&gt;etop&lt;/code&gt;, included with the Observer application, with &lt;code&gt;erl -name etop -hidden -s etop -s erlang halt -output text -node demo@127.0.0.1 -setcookie democookie&lt;/code&gt; and see how this compares to the graphical Observer&lt;/li&gt;
&lt;li&gt;Explore the trace tool builder &lt;code&gt;ttb&lt;/code&gt; and &lt;code&gt;crashdump_viewer&lt;/code&gt;, two other tools that come with the Observer application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we took a quick tour of Erlang&amp;#39;s Observer GUI. We first set up Observer for an Elixir application, then used an example app with a memory leak to explore some of Observer&amp;#39;s capabilities.&lt;/p&gt;
&lt;p&gt;We debugged a remote system, before finally suggesting some ways to dive deeper into exploring Observer&amp;#39;s many functions.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Monitor the Performance of Your Ecto for Elixir App with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/10/28/monitor-the-performance-of-your-ecto-for-elixir-app-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2025/10/28/monitor-the-performance-of-your-ecto-for-elixir-app-with-appsignal.html</id>
    <published>2025-10-28T00:00:00+00:00</published>
    <updated>2025-10-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of our two-part series, we&#039;ll use AppSignal for Elixir to monitor the performance of an Ecto application.</summary>
    <content type="html">&lt;p&gt;In part one of this series, we learned how to implement batch updates and advanced inserts in Ecto to dramatically improve database performance.&lt;/p&gt;
&lt;p&gt;But implementing these optimizations is only the first step. Ensuring they continue to work effectively in production requires professional monitoring and observability.&lt;/p&gt;
&lt;p&gt;This guide will show you how to use AppSignal for Elixir to monitor your Ecto application&amp;#39;s performance when dealing with batch data operations.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;An Elixir/Phoenix application. If you don&amp;#39;t have one, &lt;a href=&quot;https://github.com/iamaestimo/shopflow/tree/csv-imports&quot;&gt;fork the e-commerce Phoenix app&lt;/a&gt; we&amp;#39;ll be using throughout this tutorial.&lt;/li&gt;
&lt;li&gt;Elixir, Phoenix framework, and PostgreSQL installed on your local development environment.&lt;/li&gt;
&lt;li&gt;An AppSignal account. &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;Sign up for a free trial&lt;/a&gt; if you don&amp;#39;t have one.&lt;/li&gt;
&lt;li&gt;Basic experience working with Elixir and the Phoenix framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, let&amp;#39;s learn how to set up AppSignal for Elixir in our example app.&lt;/p&gt;
&lt;h2&gt;Setting Up AppSignal for Elixir&lt;/h2&gt;
&lt;p&gt;Open up the app&amp;#39;s &lt;code&gt;mix.exs&lt;/code&gt; file and add the &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;AppSignal for Elixir&lt;/a&gt; package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# mix.exs
def deps do
  [
    ...
    {:appsignal, &amp;quot;~&amp;gt; 2.8&amp;quot;},
    {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: If you have a Phoenix application, make sure you also add the AppSignal for Phoenix package, which depends on the AppSignal package.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Then run &lt;code&gt;mix deps.get&lt;/code&gt; to add the packages.&lt;/p&gt;
&lt;p&gt;Next, run &lt;code&gt;mix appsignal.install YOUR_PUSH_API_KEY&lt;/code&gt; to complete the installation. When you run this command, you will be prompted to configure how your app will be named in the AppSignal dashboard. You can also decide how the AppSignal for Elixir package will be integrated into your app, either through a configuration file (recommended), or an environment variable.&lt;/p&gt;
&lt;p&gt;Assuming the installation goes smoothly, you should start seeing some default metrics on the AppSignal dashboard after a few minutes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/initial-appsignal-dashboard.png&quot; alt=&quot;Initial AppSignal Dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s all set up.&lt;/p&gt;
&lt;h2&gt;Understanding Ecto Performance Metrics&lt;/h2&gt;
&lt;p&gt;With AppSignal installed, we can now move on to learning about some key performance indicators that AppSignal for Elixir monitors by default, namely query execution time, throughput, and N+1 queries.&lt;/p&gt;
&lt;h3&gt;Query Execution Time and Throughput&lt;/h3&gt;
&lt;p&gt;Execution time tells you how long individual database operations take, while throughput indicates how many queries your application processes over time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/query-time-and-throughput.png&quot; alt=&quot;Query time and throughput&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The AppSignal dashboard provides a convenient timeline visualization that breaks down request execution across different layers of your Phoenix app. You can see how a single request is distributed across the Phoenix endpoint and template, the router, and Ecto.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/ecto-sample-breakdown.png&quot; alt=&quot;Ecto sample breakdown&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the example shown in the screenshot above, the &lt;code&gt;GET&lt;/code&gt; request to fetch products completed successfully, taking a total of 6ms, out of which Ecto takes up 2ms — around 33% of the total execution time.&lt;/p&gt;
&lt;p&gt;When monitoring query time and throughput, these are some things to watch for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Consistent execution times&lt;/strong&gt; - You&amp;#39;re looking for consistent execution times across similar queries. If you start to experience longer execution times (compared to what you have noted as the average), you may need to look at optimizing Ecto queries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Declining throughput while execution time increases&lt;/strong&gt; - This metric could point to a growing bottleneck in your app&amp;#39;s Ecto queries.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query run times&lt;/strong&gt; - Let&amp;#39;s say you have two Ecto queries. One query takes around 10ms to execute but is being called a thousand times in an hour, while the other query takes 100ms, but is called 5 times in an hour. In such a scenario, you might think that the query that takes up more time should be prioritized for optimization, but if you turn your attention to the other and cut query time by 20%, you&amp;#39;ll probably impact your app&amp;#39;s performance much more than by fixing the longer query.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;N+1 Queries&lt;/h3&gt;
&lt;p&gt;N+1 queries occur when an initial query triggers additional queries for each returned record.&lt;/p&gt;
&lt;p&gt;Using the e-commerce app as an example, consider the code snippet below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow/catalog.ex

defmodule Shopflow.Catalog do
  ...
  def list_products_with_n_plus_one do
    products = Repo.all(Product)  # 1 query for products

    Enum.map(products, fn product -&amp;gt;
      supplier = Repo.get(Supplier, product.supplier_id)  # N queries for suppliers
      %{product | supplier: supplier}
    end)
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the &lt;code&gt;list_products_with_n_plus_one&lt;/code&gt; function fetches all products, then makes additional database calls to fetch associated suppliers, a classic N+1 query (as you can see in the log outputs below):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;[debug] Processing with ShopflowWeb.ProductController.index/2
  Parameters: %{}
  Pipelines: [:browser]
[debug] QUERY OK source=&amp;quot;products&amp;quot; db=3.9ms queue=0.2ms idle=648.6ms
SELECT p0.&amp;quot;id&amp;quot;, p0.&amp;quot;name&amp;quot;, p0.&amp;quot;description&amp;quot;, p0.&amp;quot;sku&amp;quot;, p0.&amp;quot;price&amp;quot;, p0.&amp;quot;is_active&amp;quot;, p0.&amp;quot;deleted_at&amp;quot;, p0.&amp;quot;category_id&amp;quot;, p0.&amp;quot;supplier_id&amp;quot;, p0.&amp;quot;inserted_at&amp;quot;, p0.&amp;quot;updated_at&amp;quot; FROM &amp;quot;products&amp;quot; AS p0 []
↳ Shopflow.Catalog.list_products_with_n_plus_one/0, at: lib/shopflow/catalog.ex:125
[debug] QUERY OK source=&amp;quot;suppliers&amp;quot; db=1.3ms queue=0.1ms idle=659.2ms
SELECT s0.&amp;quot;id&amp;quot;, s0.&amp;quot;name&amp;quot;, s0.&amp;quot;contact_email&amp;quot;, s0.&amp;quot;contact_phone&amp;quot;, s0.&amp;quot;is_active&amp;quot;, s0.&amp;quot;inserted_at&amp;quot;, s0.&amp;quot;updated_at&amp;quot; FROM &amp;quot;suppliers&amp;quot; AS s0 WHERE (s0.&amp;quot;id&amp;quot; = $1) [&amp;quot;f861e835-6618-4613-bd74-56667be8c01c&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The impact can be seen in the time Ecto takes to process the request — a huge 42% of the total time taken by the product listing request:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/n1-query-effect.png&quot; alt=&quot;N+1 query effect&quot;/&gt;&lt;/p&gt;
&lt;p&gt;See the measured impact on this unoptimized query:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/n1-query-impact.png&quot; alt=&quot;N+1 query impact&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s improve the query by using &lt;code&gt;Ecto.preload/3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, edit the function like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow/catalog.ex

defmodule Shopflow.Catalog do
  ...
  def list_products do
    Product
    |&amp;gt; Repo.all()
    |&amp;gt; Repo.preload(:supplier)
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And on reloading the products list, we can see how &lt;code&gt;Ecto.preload/3&lt;/code&gt; cuts down the impact metric:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/improved-preload-query.png&quot; alt=&quot;Improved query impact using preload&quot;/&gt;&lt;/p&gt;
&lt;p&gt;To a large extent, the AppSignal for Elixir integration will take care of monitoring most parts of Ecto. However, if we want to get deeper insights or coverage for scenarios that are unique to the application at hand, then we need to add custom instrumentation.&lt;/p&gt;
&lt;h2&gt;Beyond Basics — Monitoring Ecto for Elixir with AppSignal Custom Instrumentation&lt;/h2&gt;
&lt;p&gt;In part one, we learned how to insert and modify large datasets using Ecto&amp;#39;s &lt;code&gt;insert_all/3&lt;/code&gt; and the &lt;code&gt;Ecto.Multi&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;In this section, we&amp;#39;ll take the examples we started with in part one and apply &lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation.html&quot;&gt;AppSignal for Elixir&amp;#39;s custom instrumentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Monitoring Ecto Batch Inserts&lt;/h2&gt;
&lt;p&gt;In part one, we learned about the different parts that make up Ecto, like the schema, changeset, repo, and how they interact when working with batch operations.&lt;/p&gt;
&lt;p&gt;For this example, we&amp;#39;ll go further by learning how to insert bulk data into the database using CSV files. Then we&amp;#39;ll explore how to instrument these batch data operations using AppSignal for Elixir&amp;#39;s custom instrumentation.&lt;/p&gt;
&lt;p&gt;Before diving into any code examples, it&amp;#39;s important to get an overview of the CSV import process I&amp;#39;ve just mentioned.&lt;/p&gt;
&lt;p&gt;The simplified CSV import will proceed as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User clicks on a CSV import button on the frontend, which opens up a dialog for the CSV import to happen.&lt;/li&gt;
&lt;li&gt;The request is sent to the router, then on to the controller, which then leverages a &lt;code&gt;CsvImporter&lt;/code&gt; module to process the CSV and insert valid product records into the database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, let&amp;#39;s take a look at some of the parts involved in the process since this will help us understand where to leverage the custom instrumentation later on.&lt;/p&gt;
&lt;p&gt;To start us off is the user interface:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- lib/shopflow_web/controllers/product_html/index.html.heex --&amp;gt;
...

&amp;lt;button onclick=&amp;quot;document.getElementById(&amp;#39;import-modal&amp;#39;).classList.remove(&amp;#39;hidden&amp;#39;)&amp;quot;&amp;gt;
  Import CSV
&amp;lt;/button&amp;gt;

&amp;lt;!-- Modal with file upload --&amp;gt;
&amp;lt;.simple_form for={%{}} action={~p&amp;quot;/products/import&amp;quot;} multipart={true}&amp;gt;
  &amp;lt;.input field={f[:csv_file]} type=&amp;quot;file&amp;quot; accept=&amp;quot;.csv&amp;quot; /&amp;gt;
&amp;lt;/.simple_form&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next is the router:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow_web/router.ex
...
post &amp;quot;/products/import&amp;quot;, ProductController, :import
..
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the controller:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow_web/controllers/product_controller.ex
...
def import(conn, %{&amp;quot;csv_file&amp;quot; =&amp;gt; upload}) do
  case validate_csv_file(upload) do
    {:ok, file_path} -&amp;gt; # Process the file
    {:error, reason} -&amp;gt; # Show error message
  end
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, the CSV import module, with a focus on the bit that does the database insert:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow/catalog/csv_importer.ex
...
Repo.transaction(fn -&amp;gt;
  # Add timestamps and UUIDs
  products_for_insert = Enum.map(products_data, fn product_data -&amp;gt;
    product_data
    |&amp;gt; Map.put(&amp;quot;id&amp;quot;, Ecto.UUID.generate())
    |&amp;gt; Map.put(&amp;quot;inserted_at&amp;quot;, now)
    |&amp;gt; Map.put(&amp;quot;updated_at&amp;quot;, now)
  end)

  # Actual bulk insert
  {count, _} = Repo.insert_all(Product, products_for_insert)
  count
end)
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When using &lt;code&gt;Repo.insert_all/3&lt;/code&gt;, you should note that autogenerated attributes like record IDs, as well as &lt;code&gt;inserted_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt;, will not be automatically generated for you, so make sure you do this manually.&lt;/p&gt;
&lt;p&gt;With that in place, you might be wondering why we even need custom instrumentation when the AppSignal integration already gives us excellent Ecto monitoring?&lt;/p&gt;
&lt;h2&gt;Why Use Custom Instrumentation for Your Elixir App?&lt;/h2&gt;
&lt;p&gt;For starters, take a look at one of the products&amp;#39; controller request samples, with a focus on Ecto&amp;#39;s metrics (the products controller is where the CSV import happens):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/why-custom-instrument-ecto-1.png&quot; alt=&quot;Why custom instrument Ecto - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And this one:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/why-custom-instrument-ecto-2.png&quot; alt=&quot;Why custom instrument Ecto - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As you can see, even though AppSignal for Elixir covers basic Ecto metrics, to get specific data on the CSV import process would require setting up custom metrics.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s learn how to do that next.&lt;/p&gt;
&lt;h2&gt;Custom Instrumenting Ecto Batch Inserts&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation/instrumentation.html&quot;&gt;Custom instrumentation&lt;/a&gt; allows you to add detailed monitoring to specific parts of your Ecto operations that aren&amp;#39;t automatically tracked by AppSignal for Elixir&amp;#39;s default integration.&lt;/p&gt;
&lt;p&gt;By adding custom instrumentation, you can track metrics like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How long bulk operations take to complete.&lt;/li&gt;
&lt;li&gt;Success and failure rates for batch processes.&lt;/li&gt;
&lt;li&gt;Custom metrics related to your specific use case&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And more.&lt;/p&gt;
&lt;p&gt;For now, let&amp;#39;s instrument the CSV import to measure the frequency of CSV import failures, a metric that might negatively impact user experience.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a brief snippet of the instrumented &lt;code&gt;import_csv/1&lt;/code&gt; function with success/failure counters:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow/catalog/csv_importer.ex
...

def import_csv(file_path) do
    result = with {:ok, csv_data} &amp;lt;- read_and_parse_csv(file_path),
         {:ok, headers} &amp;lt;- validate_headers(csv_data),
         {:ok, products_data} &amp;lt;- validate_and_transform_data(csv_data, headers) do
      insert_products(products_data)
    end

    # Track failures with AppSignal
    case result do
      {:error, _reason} -&amp;gt;
        Appsignal.increment_counter(&amp;quot;csv_import.failure&amp;quot;)
        Appsignal.add_distribution_value(&amp;quot;csv_import.error_rate&amp;quot;, 1)
      {:ok, _} -&amp;gt;
        Appsignal.increment_counter(&amp;quot;csv_import.success&amp;quot;)
        Appsignal.add_distribution_value(&amp;quot;csv_import.error_rate&amp;quot;, 0)
      _ -&amp;gt;
        :ok
    end

    result
  end
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this code example, we&amp;#39;re using two AppSignal functions to collect custom metrics for our CSV import operation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Appsignal.increment_counter(&amp;quot;csv_import.success&amp;quot;)&lt;/code&gt;&lt;/strong&gt; - This increments a counter metric each time a CSV import completes successfully. Counters are perfect for tracking the total number of events over time, giving us visibility into import frequency and success rates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Appsignal.add_distribution_value(&amp;quot;csv_import.error_rate&amp;quot;, 0)&lt;/code&gt;&lt;/strong&gt; - This adds a value of &lt;code&gt;0&lt;/code&gt; to a distribution metric when imports succeed. Distribution metrics help us track statistical data like averages, percentiles, and patterns. By recording &lt;code&gt;0&lt;/code&gt; for successful imports (and &lt;code&gt;1&lt;/code&gt; for failures), we can calculate error rates and monitor import reliability trends over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These custom metrics complement AppSignal&amp;#39;s automatic Ecto instrumentation by providing business-specific insights that help us understand not just database performance, but also the success patterns of the CSV import operation.&lt;/p&gt;
&lt;p&gt;The results are seen in the custom dashboard below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/csv-import-failure-counts.png&quot; alt=&quot;CSV import failure counts&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: The process of adding custom dashboards is not included in this tutorial, but you can follow &lt;a href=&quot;https://docs.appsignal.com/metrics/dashboards.html&quot;&gt;this guide&lt;/a&gt; to learn more.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this guide, we explored how to effectively monitor Ecto performance using AppSignal for Elixir, building on the batch data techniques we learned in part one.&lt;/p&gt;
&lt;p&gt;We covered the setup process, examined a few key performance metrics like query execution time, throughput, and N+1 queries, and learned how to implement custom instrumentation for scenarios that require deeper monitoring.&lt;/p&gt;
&lt;p&gt;With the lessons covered in this tutorial, you now have the skills to identify and measure various performance bottlenecks in your Ecto applications.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Batch Updates and Advanced Inserts in Ecto for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/10/07/batch-updates-and-advanced-inserts-in-ecto-for-elixir.html"/>
    <id>https://blog.appsignal.com/2025/10/07/batch-updates-and-advanced-inserts-in-ecto-for-elixir.html</id>
    <published>2025-10-07T00:00:00+00:00</published>
    <updated>2025-10-07T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this first part of a two-part series, we&#039;ll explore Ecto&#039;s powerful batch update and advanced insert capabilities.</summary>
    <content type="html">&lt;p&gt;When you build Elixir applications, you&amp;#39;ll likely encounter scenarios where you need to handle large datasets efficiently. Whether you&amp;#39;re importing user data from a CSV file, updating thousands of product prices, or synchronizing data from external APIs, performing operations one record at a time can quickly become a performance bottleneck.&lt;/p&gt;
&lt;p&gt;In this two-part tutorial, we&amp;#39;ll start by exploring Ecto&amp;#39;s powerful batch update and advanced insert capabilities for handling bulk data operations. Then, in the second part, we&amp;#39;ll learn how to integrate AppSignal for Elixir to build an observability layer on top of Ecto to catch errors and any performance issues that could arise.&lt;/p&gt;
&lt;p&gt;Before we begin, you&amp;#39;ll need a few things set up.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Elixir, the Phoenix framework and PostgreSQL installed and running in your local development environment.&lt;/li&gt;
&lt;li&gt;A Phoenix application. If you don&amp;#39;t have one ready, &lt;a href=&quot;https://github.com/iamaestimo/shopflow&quot;&gt;fork the example app&lt;/a&gt; we&amp;#39;ll be using throughout this tutorial.&lt;/li&gt;
&lt;li&gt;Basic Elixir and Phoenix framework experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Introducing Ecto for Elixir&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elixir-ecto/ecto&quot;&gt;Ecto&lt;/a&gt; is Elixir&amp;#39;s database toolkit that acts as a bridge between your application and relational databases like PostgreSQL. It provides type-safe query building, automated migrations, and data validation, making complex data operations simple and reliable.&lt;/p&gt;
&lt;h3&gt;Ecto&amp;#39;s Architecture&lt;/h3&gt;
&lt;p&gt;At its core, Ecto is built around three fundamental components that work together to provide a complete database abstraction layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Schema.html&quot;&gt;Schemas&lt;/a&gt;&lt;/strong&gt; act as the structural foundation, defining how data maps to database tables without containing any business logic. Schemas establish field types, relationships, and table mappings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html&quot;&gt;Changesets&lt;/a&gt;&lt;/strong&gt; form the business logic layer, handling validation, data transformation, and change tracking. They take raw input data and a schema struct, then produce a validated, trackable representation of what should change in the database.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html&quot;&gt;Repo&lt;/a&gt;&lt;/strong&gt; translates Ecto operations into actual SQL queries, while managing database connections, transactions, and query execution.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, we&amp;#39;ll take a look at how Ecto handles single database operations, the challenges that come with it, and why batch operations matter.&lt;/p&gt;
&lt;h3&gt;How Standard Database Operations Work in Ecto for Elixir&lt;/h3&gt;
&lt;p&gt;For individual database operations like &lt;em&gt;inserts&lt;/em&gt;, &lt;em&gt;updates&lt;/em&gt;, or &lt;em&gt;deletes&lt;/em&gt;, Ecto validates your data through changesets before sending SQL commands to the database. This approach works well for single-record operations but can become a performance bottleneck when handling a large number of records.&lt;/p&gt;
&lt;p&gt;Before we learn how standard operations work through an example, let&amp;#39;s get an overview of the app we&amp;#39;ll be using moving forward.&lt;/p&gt;
&lt;h2&gt;Introducing Our Example Phoenix App&lt;/h2&gt;
&lt;p&gt;Our example app is a Phoenix ecommerce app managing products, suppliers, orders, products, and inventory for multiple stores. The app&amp;#39;s database is represented below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/shopflow-database-diagram.png&quot; alt=&quot;Shopflow Database Diagram&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now that we have an idea of how our app is structured (at least on the database level), in the next section, we&amp;#39;ll learn how to do a normal data insert using Ecto.&lt;/p&gt;
&lt;h2&gt;Standard Inserts with Ecto&lt;/h2&gt;
&lt;p&gt;A database &lt;em&gt;insert&lt;/em&gt; operation creates a new record in a table. In Ecto, this process involves several steps: first, you create a changeset that validates and transforms your data according to your schema&amp;#39;s rules, then Ecto converts this changeset into the appropriate &lt;code&gt;SQL INSERT&lt;/code&gt; statement and executes it against the database.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-10/how-ecto-works.png&quot; alt=&quot;How Ecto Works&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s learn about the role of each Ecto component.&lt;/p&gt;
&lt;h3&gt;The Schema’s Role&lt;/h3&gt;
&lt;p&gt;We first start with the supplier schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow/suppliers/supplier.ex

defmodule Shopflow.Suppliers.Supplier do
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id

  schema &amp;quot;suppliers&amp;quot; do
    field :name, :string
    field :contact_email, :string
    field :contact_phone, :string
    field :is_active, :boolean, default: false

    timestamps(type: :utc_datetime)
  end

  @doc false
  def changeset(supplier, attrs) do
    supplier
    |&amp;gt; cast(attrs, [:name, :contact_email, :contact_phone, :is_active])
    |&amp;gt; validate_required([:name])
    |&amp;gt; validate_format(:contact_email, ~r/@/)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This schema definition establishes several important aspects of our &lt;code&gt;Supplier&lt;/code&gt; model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Primary key configuration&lt;/strong&gt;: Uses &lt;code&gt;:binary_id&lt;/code&gt; with auto-generation, creating UUID-based primary keys instead of sequential integers for better distribution across systems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foreign key type&lt;/strong&gt;: Sets &lt;code&gt;:binary_id&lt;/code&gt; as the default foreign key type to maintain consistency with the primary key format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Field definitions&lt;/strong&gt;: Defines four main fields — &lt;code&gt;name&lt;/code&gt; (string), &lt;code&gt;contact_email&lt;/code&gt; (string), &lt;code&gt;contact_phone&lt;/code&gt; (string), and &lt;code&gt;is_active&lt;/code&gt; (boolean with &lt;code&gt;false&lt;/code&gt; default).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timestamps&lt;/strong&gt;: Automatically adds &lt;code&gt;inserted_at&lt;/code&gt; and &lt;code&gt;updated_at&lt;/code&gt; fields using UTC datetime format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validation rules&lt;/strong&gt;: The changeset function enforces that &lt;code&gt;name&lt;/code&gt; is required and &lt;code&gt;contact_email&lt;/code&gt; follows a basic email format pattern.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data casting&lt;/strong&gt;: Only allows specific fields to be modified through the &lt;code&gt;cast/3&lt;/code&gt; function, providing a controlled interface for data changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Repo’s Role&lt;/h3&gt;
&lt;p&gt;Next, we have the repo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shopflow/repo.ex

defmodule Shopflow.Repo do
  use Ecto.Repo,
    otp_app: :shopflow,
    adapter: Ecto.Adapters.Postgres
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The repo serves as the database interface layer: the bridge between our Elixir code and the PostgreSQL database, handling all database operations for our schemas.&lt;/p&gt;
&lt;p&gt;With these in place, we can now create a database record by performing an insert.&lt;/p&gt;
&lt;h3&gt;Creating a Record in the Database&lt;/h3&gt;
&lt;p&gt;With the application running, open another terminal and run &lt;code&gt;iex -S mix&lt;/code&gt; to start an interactive Elixir shell. We&amp;#39;ll use it to create a new supplier record with the commands below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# 1. Alias the Repo and Supplier schema to have access them in the shell
alias Shopflow.Repo
alias Shopflow.Suppliers.Supplier

# 2. Define attributes for the new supplier
attrs = %{
  name: &amp;quot;Spaceship suppliers&amp;quot;,          # Required field
  contact_email: &amp;quot;info@example.com&amp;quot;,  # Validated by regex (~r/@/)
  contact_phone: &amp;quot;123-456-7890&amp;quot;,      # Optional
  is_active: true                     # Default is false
}

# 3. Build a changeset to validate and prepare the data
changeset = Supplier.changeset(%Supplier{}, attrs)

# 4. Insert the changeset into the database using the Repo
Repo.insert(changeset)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If successful, you’ll see a map of the inserted supplier, including the generated &lt;code&gt;id&lt;/code&gt; and timestamps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;{:ok,
 %Shopflow.Suppliers.Supplier{
   __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, &amp;quot;suppliers&amp;quot;&amp;gt;,
   id: &amp;quot;f861e835-6618-4613-bd74-56667be8c01c&amp;quot;,
   name: &amp;quot;Spaceship suppliers&amp;quot;,
   contact_email: &amp;quot;info@example.com&amp;quot;,
   contact_phone: &amp;quot;123-456-7890&amp;quot;,
   is_active: true,
   inserted_at: ~U[2025-08-26 09:21:00Z],
   updated_at: ~U[2025-08-26 09:21:00Z]
 }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While the single-record approach shown above works perfectly for individual operations, it becomes problematic when dealing with large datasets.&lt;/p&gt;
&lt;h2&gt;The Performance Problem and Why Batch Operations Matter&lt;/h2&gt;
&lt;p&gt;Each individual insert requires a separate database connection and network round-trip, as you can see when we created the supplier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(5)&amp;gt; Repo.insert(changeset)
[debug] QUERY OK source=&amp;quot;suppliers&amp;quot; db=6.2ms decode=1.5ms queue=0.8ms idle=1234.3ms
INSERT INTO &amp;quot;suppliers&amp;quot; (&amp;quot;name&amp;quot;,&amp;quot;contact_email&amp;quot;,&amp;quot;contact_phone&amp;quot;,&amp;quot;is_active&amp;quot;,&amp;quot;inserted_at&amp;quot;,&amp;quot;updated_at&amp;quot;,&amp;quot;id&amp;quot;) VALUES ($1,$2,$3,$4,$5,$6,$7) [&amp;quot;Spaceship suppliers&amp;quot;, &amp;quot;info@example.com&amp;quot;, &amp;quot;123-456-7890&amp;quot;, true, ~U[2025-08-26 09:21:00Z], ~U[2025-08-26 09:21:00Z], &amp;quot;f861e835-6618-4613-bd74-56667be8c01c&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create 10,000 suppliers, you make 10,000 separate database calls, which is very inefficient. To make matters worse, you lose atomicity — if the 500th supplier fails to insert due to a validation error, the previous 499 records will have already been committed to the database, leaving your data in an inconsistent state.&lt;/p&gt;
&lt;p&gt;This is where Ecto&amp;#39;s batch operations become essential.&lt;/p&gt;
&lt;h2&gt;Batch Inserts in Ecto: Inserting Multiple Records Efficiently&lt;/h2&gt;
&lt;p&gt;Batch inserts in Ecto allow you to create multiple database records in a single, efficient operation using &lt;code&gt;Repo.insert_all/3&lt;/code&gt;. Unlike individual inserts that require separate database round-trips for each record, batch inserts compile all your data into a single SQL statement that creates hundreds or thousands of records at once.&lt;/p&gt;
&lt;h3&gt;An Example: Bulk Inserting Supplier Data&lt;/h3&gt;
&lt;p&gt;In the previous example, we used &lt;code&gt;Repo.insert/2&lt;/code&gt; to insert a single supplier record into the database, with the changeset performing validations and other checks before insertion into the database.&lt;/p&gt;
&lt;p&gt;For a bulk insert, we&amp;#39;ll make use of &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#c:insert_all/3&quot;&gt;&lt;code&gt;Repo.insert_all/3&lt;/code&gt;&lt;/a&gt; to insert a bunch of suppliers into the database.&lt;/p&gt;
&lt;h3&gt;Preparing Data for Batch Insertion&lt;/h3&gt;
&lt;p&gt;To begin with, prepare a relevant data source. In my case, I prepared a CSV with around 1,000 supplier records.&lt;/p&gt;
&lt;p&gt;The thing to note when preparing data for batch insertion is to make sure the data is in the right format. Remember, batch inserts do not utilize a schema&amp;#39;s changeset to help with any validations or data checks, which means data validation is up to you.&lt;/p&gt;
&lt;h3&gt;Using &lt;code&gt;Repo.insert_all/3&lt;/code&gt; To Bulk Insert Data&lt;/h3&gt;
&lt;p&gt;Next, with the server running in one terminal, open another terminal and create a new iEx session with &lt;code&gt;iex -S mix&lt;/code&gt;, then run the command below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;alias NimbleCSV.RFC4180, as: Parser
alias Shopflow.Repo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Prior installation of &lt;a href=&quot;https://github.com/dashbitco/nimble_csv&quot;&gt;NimbleCSV&lt;/a&gt; or any other CSV library is required to process CSV files.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;First, we alias NimbleCSV and the repo to make them available in the &lt;code&gt;iEx&lt;/code&gt; session. Then, we run the following commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;#1: We get the location of the CSV file
csv_content = File.read!(&amp;quot;path-to-csv-file&amp;quot;)

#2: Parse the CSV file
parsed_rows = Parser.parse_string(csv_content)

#3: Use Repo.insert_all/3 to do the bulk insert
Repo.insert_all(
  &amp;quot;suppliers&amp;quot;,
  Enum.map(parsed_rows, fn [n, e, p, a] -&amp;gt;
    %{
      id: Ecto.UUID.generate() |&amp;gt; Ecto.UUID.dump!(),
      name: n,
      contact_email: e,
      contact_phone: p,
      is_active: String.downcase(a) == &amp;quot;true&amp;quot;,
      inserted_at: DateTime.utc_now(),
      updated_at: DateTime.utc_now()
    }
  end)
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, each CSV row is converted into a database-ready map with generated UUIDs, string values are converted to appropriate data types, timestamps are added, and finally, all records are inserted into the suppliers table in a single transaction using &lt;code&gt;Repo.insert_all/3&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The Challenges of Batch Inserts&lt;/h2&gt;
&lt;p&gt;While &lt;code&gt;Repo.insert_all/3&lt;/code&gt; provides excellent performance for bulk operations, it comes with several important limitations that developers need to understand.&lt;/p&gt;
&lt;h3&gt;Validation and Error Handling&lt;/h3&gt;
&lt;p&gt;Unlike individual inserts that leverage Ecto&amp;#39;s changeset system, batch inserts bypass validation entirely, meaning data integrity checks must be handled manually before insertion.&lt;/p&gt;
&lt;p&gt;For example, we know that database-level constraints like unique indexes can cause the entire batch to fail if even a single record violates them. A good strategy to deal with this is to use a combination of smaller batches and Ecto&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#c:transaction/2&quot;&gt;transaction API&lt;/a&gt;, as in the example below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;batch_size = 100
suppliers_attrs
|&amp;gt; Enum.chunk_every(batch_size)
|&amp;gt; Enum.each(fn batch -&amp;gt;
  Repo.transaction(fn -&amp;gt;
    # Attempt to insert the batch
    Repo.insert_all(&amp;quot;suppliers&amp;quot;, batch)
  rescue
    Ecto.ConstraintError -&amp;gt;
      # Handle duplicate email (or other constraint) here
      IO.puts(&amp;quot;Batch failed due to constraint violation. Retrying...&amp;quot;)
  end)
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We first divide the &lt;code&gt;suppliers_attrs&lt;/code&gt; into batches of 100 records each, then process each batch sequentially, with each batch being inserted into the database using &lt;code&gt;Repo.insert_all/3&lt;/code&gt; wrapped in a database transaction. This will rollback the transaction should an error occur (in this case, we try to rescue the error and handle it in some way).&lt;/p&gt;
&lt;h3&gt;Limited Association Handling&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Repo.insert_all/3&lt;/code&gt; cannot directly handle associations (for example, linking suppliers to products). In such cases, you must handle the association manually by first creating the parent records, then referencing the parent record IDs when creating the child records.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s switch gears to the subject of batch updates.&lt;/p&gt;
&lt;h2&gt;Batch Updates&lt;/h2&gt;
&lt;p&gt;Batch updates involve updating a number of records all at once. They introduce some unique challenges, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Interdependencies&lt;/strong&gt;: Updates often affect associated records. For example, changing a supplier’s status requires updating linked products at the same time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Partial failures&lt;/strong&gt;: A single invalid change (for instance, violating a uniqueness constraint can derail the entire batch).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrency risks&lt;/strong&gt;: Competing updates to the same records can cause race conditions (for example, overlapping inventory adjustments).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, what options do you have if you want to perform a stress-free batch update? One solution is to use &lt;code&gt;Ecto.Multi&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Handling Batch Updates With &lt;code&gt;Ecto.Multi&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Ecto.Multi&lt;/code&gt; is a tool that lets you bundle multiple database operations (inserts, updates, and deletes) into a single chunk. &lt;code&gt;Ecto.Multi&lt;/code&gt; solves the critical issues that come with bulk updates, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Atomicity&lt;/strong&gt; - Ensuring all steps succeed (or none do).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dependency management&lt;/strong&gt; - Making sure associations and dependencies are handled efficiently.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error isolation&lt;/strong&gt; - With &lt;code&gt;Ecto.Multi&lt;/code&gt;, each step is named, which makes it very easy to pinpoint where a failure occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;An Example Using &lt;code&gt;Ecto.Multi&lt;/code&gt; to Run a Batch Update&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s say we need to deactivate a supplier and mark all their products as discontinued. How can we do this effectively?&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;Ecto.Multi&lt;/code&gt;, we could run code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(7)&amp;gt;
alias Ecto.Multi
alias Shopflow.Suppliers.Supplier
alias Shopflow.Products.Product

# Target supplier ID to deactivate
supplier_id = &amp;quot;f861e835-6618-4613-bd74-56667be8c01c&amp;quot;

# Compose multi-step update
multi =
  Multi.new()
  # Step 1: Deactivate the supplier
  |&amp;gt; Multi.update(:deactivate_supplier,
    Supplier
    |&amp;gt; where([s], s.id == ^supplier_id)
    |&amp;gt; select([s], s),  # Fetch the supplier record
    set: [is_active: false]  # Set active flag to false
  )
  # Step 2: Mark all their products as inactive
  |&amp;gt; Multi.update_all(:discontinue_products,
    Product
    |&amp;gt; where([p], p.supplier_id == ^supplier_id),
    set: [is_active: false]  # Update all matching products
  )

# Execute the transaction
case Repo.transaction(multi) do
  {:ok, _results} -&amp;gt;
    IO.puts(&amp;quot;Supplier and products updated successfully!&amp;quot;)
  {:error, step, reason, _} -&amp;gt;
    IO.puts(&amp;quot;Update failed at step &amp;#39;#{step}&amp;#39;: #{inspect(reason)}&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use &lt;code&gt;Ecto.Multi&lt;/code&gt; wrapped in a database transaction (so a rollback can happen, in case of errors) to create a multi-step update. The update starts with a step called &lt;code&gt;:deactive_supplier&lt;/code&gt;, which finds the specific supplier we want. Then, the &lt;code&gt;:discontinue_products&lt;/code&gt; step sets the &lt;code&gt;is_active&lt;/code&gt; flag as &lt;code&gt;false&lt;/code&gt; on any product belonging to the supplier.&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it for this first part!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this tutorial, we learned how to handle bulk data operations efficiently using Ecto&amp;#39;s powerful batch capabilities. We explored the performance limitations of single-record operations and saw how &lt;code&gt;Repo.insert_all/3&lt;/code&gt; can dramatically improve insertion performance for large datasets. We also found out about the challenges that come with batch operations, and how we can use &lt;code&gt;Ecto.Multi&lt;/code&gt; to ensure data consistency when doing batch updates.&lt;/p&gt;
&lt;p&gt;In part two of this series, we&amp;#39;ll integrate AppSignal for Elixir into our app to build an observability layer that monitors these batch operations. This will help you catch performance bottlenecks and errors before they impact your production applications.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Advanced Debugging in Elixir with IO.inspect</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/09/23/advanced-debugging-in-elixir-with-io-inspect.html"/>
    <id>https://blog.appsignal.com/2025/09/23/advanced-debugging-in-elixir-with-io-inspect.html</id>
    <published>2025-09-23T00:00:00+00:00</published>
    <updated>2025-09-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s explore both the fundamentals and advanced patterns for using IO.inspect effectively.</summary>
    <content type="html">&lt;p&gt;When writing Elixir, most developers quickly get familiar with &lt;code&gt;IO.inspect&lt;/code&gt; as a quick way to see what&amp;#39;s happening inside their code. But what many overlook is that &lt;code&gt;IO.inspect&lt;/code&gt; is far more powerful than just a method that prints a variable to the console.&lt;/p&gt;
&lt;p&gt;In fact, with the right options and placement, &lt;code&gt;IO.inspect&lt;/code&gt; can become a precise, highly targeted debugging tool, one that doesn&amp;#39;t interrupt your program flow and works seamlessly with Elixir&amp;#39;s functional pipelines.&lt;/p&gt;
&lt;p&gt;This post will walk you through both the fundamentals and advanced patterns for using &lt;code&gt;IO.inspect&lt;/code&gt; effectively. By the end, you&amp;#39;ll know how to control output formatting, label your prints for clarity, debug concurrent processes, and even integrate conditional or file-based inspection.&lt;/p&gt;
&lt;h2&gt;The Basics of &lt;code&gt;IO.inspect&lt;/code&gt; for Elixir&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/IO.html#inspect/2&quot;&gt;&lt;code&gt;IO.inspect&lt;/code&gt;&lt;/a&gt; is defined like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IO.inspect(item, opts \\ [])
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;item&lt;/code&gt;: Any Elixir value you want to inspect.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opts&lt;/code&gt;: Keyword list of options that controls how the term is printed, as defined in &lt;a href=&quot;https://hexdocs.pm/elixir/Inspect.Opts.html&quot;&gt;&lt;code&gt;Inspect.Opts&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default, it writes the inspected value to the standard output (&lt;code&gt;:stdio&lt;/code&gt;) and then returns the term unchanged.&lt;/p&gt;
&lt;p&gt;That last part is key. Because it returns the term, you can drop it anywhere in a function or pipeline without breaking the flow.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Demo do
  def run do
    IO.inspect(%{name: &amp;quot;Alice&amp;quot;, age: 30})
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prints:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;%{age: 30, name: &amp;quot;Alice&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Caveat: When &lt;code&gt;IO.inspect&lt;/code&gt; Is the Last Call in a Function&lt;/h3&gt;
&lt;p&gt;Because &lt;code&gt;IO.inspect&lt;/code&gt; returns its argument, if it&amp;#39;s the &lt;strong&gt;last expression in your function&lt;/strong&gt;, that inspected value becomes the function&amp;#39;s return value.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s fine if you &lt;em&gt;intend&lt;/em&gt; to return it, but it can lead to subtle bugs if you were only printing it for debugging and expected a different return.&lt;/p&gt;
&lt;p&gt;Take this example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def fetch_user(id) do
  Repo.get(User, id)
  |&amp;gt; IO.inspect(label: &amp;quot;Fetched user&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the function returns the user struct as normal, which is fine.&lt;/p&gt;
&lt;p&gt;Now, consider:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def log_and_return do
  IO.inspect(&amp;quot;Done!&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returns &lt;code&gt;&amp;quot;Done!&amp;quot;&lt;/code&gt; instead of, say, &lt;code&gt;:ok&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want to print something &lt;strong&gt;but return a different value&lt;/strong&gt;, make the return explicit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def log_and_return do
  IO.inspect(&amp;quot;Done!&amp;quot;)
  :ok
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or if you&amp;#39;re in a pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;value
|&amp;gt; IO.inspect(label: &amp;quot;Debug&amp;quot;)
|&amp;gt; do_something_else()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; if &lt;code&gt;IO.inspect&lt;/code&gt; is the last expression in a function, be explicit about what you want to return.&lt;/p&gt;
&lt;h3&gt;Strategic Placement with the Pipe Operator&lt;/h3&gt;
&lt;p&gt;Because &lt;code&gt;IO.inspect&lt;/code&gt; returns its argument, it fits perfectly in the middle of a pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;users
|&amp;gt; IO.inspect(label: &amp;quot;Before filtering&amp;quot;)
|&amp;gt; Enum.filter(&amp;amp; &amp;amp;1.active)
|&amp;gt; IO.inspect(label: &amp;quot;After filtering&amp;quot;)
|&amp;gt; Enum.map(&amp;amp; &amp;amp;1.name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This lets you peek into the data flow at exactly the point you want, without rewriting your code into intermediate variables.&lt;/p&gt;
&lt;p&gt;A neat trick is to place multiple &lt;code&gt;IO.inspect&lt;/code&gt; calls at different stages, each with a distinct label, so you can see how the data changes step by step.&lt;/p&gt;
&lt;h2&gt;Using Labels for Clarity in Elixir&lt;/h2&gt;
&lt;p&gt;Without labels, multiple inspection outputs can be hard to tell apart. The &lt;code&gt;label&lt;/code&gt; option solves this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IO.inspect(data, label: &amp;quot;After filtering&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prints:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;After filtering: [%{name: &amp;quot;Alice&amp;quot;}, %{name: &amp;quot;Bob&amp;quot;}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When debugging a pipeline with several inspect points, labels make the output self-describing. This is especially useful when you&amp;#39;re debugging multiple similar data structures in the same run.&lt;/p&gt;
&lt;h2&gt;Pretty Printing and Formatting Output&lt;/h2&gt;
&lt;p&gt;Sometimes, especially with large maps or deeply nested lists, the default single-line output is hard to read. That&amp;#39;s where formatting options defined in &lt;a href=&quot;https://hexdocs.pm/elixir/Inspect.Opts.html&quot;&gt;&lt;code&gt;Inspect.Opts&lt;/code&gt;&lt;/a&gt; come in.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:pretty&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If set to &lt;code&gt;true&lt;/code&gt;, enables pretty printing.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:limit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limits the number of items inspected for tuples, bitstrings, maps, lists and any other collection of items, with the exception of printable strings and printable charlists which use the &lt;code&gt;:printable_limit&lt;/code&gt; option. If you don&amp;#39;t want to limit the number of items to a particular number, use &lt;code&gt;:infinity&lt;/code&gt;. It accepts a positive integer or &lt;code&gt;:infinity&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;50&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:printable_limit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Limits the number of characters that are inspected on printable strings and printable charlists. You can use &lt;a href=&quot;https://hexdocs.pm/elixir/String.html#printable?/1&quot;&gt;&lt;code&gt;String.printable?/1&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/elixir/List.html#ascii_printable?/1&quot;&gt;&lt;code&gt;List.ascii_printable?/1&lt;/code&gt;&lt;/a&gt; to check if a given string or charlist is printable. If you don&amp;#39;t want to limit the number of characters to a particular number, use &lt;code&gt;:infinity&lt;/code&gt;. It accepts a positive integer or &lt;code&gt;:infinity&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4096&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:width&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of characters per line used when pretty is &lt;code&gt;true&lt;/code&gt; or when printing to IO devices. Set to &lt;code&gt;0&lt;/code&gt; to force each item to be printed on its own line. If you don&amp;#39;t want to limit the number of items to a particular number, use &lt;code&gt;:infinity&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;80&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:charlists&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;When &lt;code&gt;:as_charlists&lt;/code&gt;, all lists will be printed as charlists, non-printable elements will be escaped. When &lt;code&gt;:as_lists&lt;/code&gt;, all lists will be printed as lists. When the default &lt;code&gt;:infer&lt;/code&gt;, the list will be printed as a charlist if it is printable, otherwise as a list. See &lt;a href=&quot;https://hexdocs.pm/elixir/List.html#ascii_printable?/1&quot;&gt;&lt;code&gt;List.ascii_printable?/1&lt;/code&gt;&lt;/a&gt; to learn when a charlist is printable.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;:infer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;data = for i &amp;lt;- 1..100 do
  %{id: i, value: String.duplicate(&amp;quot;x&amp;quot;, i)}
end

IO.inspect(data, pretty: true, limit: 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prints:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;[
  %{id: 1, value: &amp;quot;x&amp;quot;},
  %{id: 2, value: &amp;quot;xx&amp;quot;},
  %{id: 3, value: &amp;quot;xxx&amp;quot;},
  %{id: 4, ...},
  %{...},
  ...
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we can see the first five entries, and the rest are summarized with &lt;code&gt;...&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Coloring and Styling Output&lt;/h3&gt;
&lt;p&gt;Elixir&amp;#39;s inspect options support syntax coloring: very handy when your terminal is full of logs.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IO.inspect(data,
  syntax_colors: [
    atom: :blue,
    string: :green,
    number: :red
  ],
  pretty: true
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes atoms blue, strings green, and numbers red in your console output.&lt;/p&gt;
&lt;p&gt;Colors can be any &lt;a href=&quot;https://hexdocs.pm/elixir/IO.ANSI.html#t:ansidata/0&quot;&gt;&lt;code&gt;IO.ANSI.ansidata/0&lt;/code&gt;&lt;/a&gt; as accepted by &lt;a href=&quot;https://hexdocs.pm/elixir/IO.ANSI.html#format/1&quot;&gt;&lt;code&gt;IO.ANSI.format/1&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to use the default colors (like what is used in &lt;code&gt;IEx&lt;/code&gt;), you can use &lt;a href=&quot;https://hexdocs.pm/elixir/IO.ANSI.html#syntax_colors/0&quot;&gt;&lt;code&gt;IO.ANSI.syntax_colors/0&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IO.inspect(data,
  syntax_colors: IO.ANSI.syntax_colors(),
  pretty: true
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The colors are only visible if your terminal supports ANSI colors.&lt;/p&gt;
&lt;h3&gt;Conditional Inspection&lt;/h3&gt;
&lt;p&gt;Sometimes you only want to inspect if a certain condition is true: for example, when a debug flag is enabled or when a value crosses a threshold.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example with a debug flag:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def debug(term) do
  if Application.get_env(:my_app, :debug) do
    IO.inspect(term, label: &amp;quot;Debug&amp;quot;)
  end
  term
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the function like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;users
|&amp;gt; Enum.filter(&amp;amp; &amp;amp;1.active)
|&amp;gt; debug()
|&amp;gt; Enum.map(&amp;amp; &amp;amp;1.name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can toggle the output by setting &lt;code&gt;config :my_app, :debug, true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Capturing Inspect Output Instead of Printing&lt;/h3&gt;
&lt;p&gt;If you want to get the inspected form of a value without printing it, use &lt;a href=&quot;https://hexdocs.pm/elixir/Inspect.html#inspect/2&quot;&gt;&lt;code&gt;inspect/2&lt;/code&gt;&lt;/a&gt; (without the &lt;code&gt;IO.&lt;/code&gt; prefix):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;string_representation = inspect(data, pretty: true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is useful if you want to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write the debug output to a file&lt;/li&gt;
&lt;li&gt;Send it to a logging service&lt;/li&gt;
&lt;li&gt;Include it in an exception message&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;File.write!(&amp;quot;debug.log&amp;quot;, inspect(data, pretty: true))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also redirect &lt;code&gt;IO.inspect&lt;/code&gt; output to another device:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IO.inspect(data, label: &amp;quot;Debug&amp;quot;, device: :stderr)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Debugging Concurrency and Async Code&lt;/h2&gt;
&lt;p&gt;When you use &lt;code&gt;IO.inspect&lt;/code&gt; in async code, the output may arrive out of order, making it hard to follow. Adding identifiers or timestamps can help.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;tasks =
  for id &amp;lt;- 1..3 do
    Task.async(fn -&amp;gt;
      IO.inspect(self(), label: &amp;quot;PID #{id}&amp;quot;)
      :timer.sleep(100)
      id * id
    end)
  end

Enum.map(tasks, &amp;amp;Task.await/1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Prints:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;PID 3: #PID&amp;lt;0.112.0&amp;gt;
PID 2: #PID&amp;lt;0.111.0&amp;gt;
PID 1: #PID&amp;lt;0.110.0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Including the PID or a unique request ID in your label helps you trace which output belongs to which process.&lt;/p&gt;
&lt;h2&gt;Advanced Trick: Inspecting and Pattern Matching in One Go&lt;/h2&gt;
&lt;p&gt;You can combine pattern matching with inspection to see exactly what&amp;#39;s being matched:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%{id: id} = IO.inspect(user, label: &amp;quot;User before insert&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This inspects the &lt;code&gt;user&lt;/code&gt; variable before pattern matching extracts the &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can also place &lt;code&gt;IO.inspect&lt;/code&gt; inside a guard to conditionally print:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;case user do
  %{role: :admin} = u -&amp;gt; IO.inspect(u, label: &amp;quot;Admin user&amp;quot;)
  _ -&amp;gt; :ok
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this last example, &amp;quot;Admin user&amp;quot; will only be printed if the user has the role &lt;code&gt;:admin&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Using &lt;code&gt;dbg/2&lt;/code&gt; for Richer Inspection&lt;/h2&gt;
&lt;p&gt;Since Elixir &lt;strong&gt;1.14&lt;/strong&gt;, we have &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#dbg/2&quot;&gt;&lt;code&gt;dbg/2&lt;/code&gt;&lt;/a&gt;, a built-in debugging helper that works like &lt;code&gt;IO.inspect&lt;/code&gt; but &lt;strong&gt;also shows the code expression&lt;/strong&gt; that produced the value.&lt;/p&gt;
&lt;p&gt;You can use it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;users |&amp;gt; Enum.filter(&amp;amp; &amp;amp;1.active) |&amp;gt; dbg()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which prints:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;users #=&amp;gt; [%{active: false, name: &amp;quot;Alice&amp;quot;}, %{active: true, name: &amp;quot;Bob&amp;quot;}]
|&amp;gt; Enum.filter(&amp;amp; &amp;amp;1.active) #=&amp;gt; [%{active: true, name: &amp;quot;Bob&amp;quot;}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes it much easier to understand &lt;em&gt;where&lt;/em&gt; in your code the inspected value is coming from, especially when you&amp;#39;re inspecting multiple similar-looking values.&lt;/p&gt;
&lt;p&gt;You can also pass options similar to &lt;code&gt;IO.inspect&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;dbg(users, label: &amp;quot;Active users&amp;quot;, pretty: true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are the key differences with &lt;code&gt;IO.inspect&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Shows the code expression&lt;/strong&gt; automatically.&lt;/li&gt;
&lt;li&gt;Output format is slightly more verbose.&lt;/li&gt;
&lt;li&gt;Same return behavior, returns the inspected value, so you can keep it in a pipeline.&lt;/li&gt;
&lt;li&gt;Best for &lt;strong&gt;interactive debugging&lt;/strong&gt; during development.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;When &lt;code&gt;IO.inspect&lt;/code&gt; is Not Enough&lt;/h2&gt;
&lt;p&gt;While &lt;code&gt;IO.inspect&lt;/code&gt; is a fantastic quick-and-dirty tool, there are times when you need more powerful debugging:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://hexdocs.pm/iex/IEx.html#pry/0&quot;&gt;&lt;code&gt;IEx.pry&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;: drops you into an interactive REPL inside the running process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.erlang.org/doc/apps/observer/observer.html#start/0&quot;&gt;&lt;code&gt;:observer.start/0&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;: Erlang&amp;#39;s GUI for monitoring processes, memory, and more.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The trick is to know when to reach for &lt;code&gt;IO.inspect&lt;/code&gt; and when to switch to one of these other tools.&lt;/p&gt;
&lt;h3&gt;Setting Default Options for &lt;code&gt;IO.inspect&lt;/code&gt; in IEx&lt;/h3&gt;
&lt;p&gt;When using &lt;code&gt;IEx&lt;/code&gt;, you can configure the default options for &lt;code&gt;IO.inspect&lt;/code&gt; using the &lt;a href=&quot;https://hexdocs.pm/iex/IEx.html#configure/1&quot;&gt;&lt;code&gt;IEx.configure/1&lt;/code&gt;&lt;/a&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IEx.configure(
  colors: [
    syntax_colors: [
      number: :light_yellow,
      atom: :light_cyan,
      string: :light_black,
      boolean: :red,
      nil: [:magenta, :bright]
    ],
    ls_directory: :cyan,
    ls_device: :yellow,
    doc_code: :green,
    doc_inline_code: :magenta,
    doc_headings: [:cyan, :underline],
    doc_title: [:cyan, :bright, :underline]
  ]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can easily put this in your &lt;a href=&quot;https://hexdocs.pm/iex/IEx.html#module-configuring-the-shell&quot;&gt;&lt;code&gt;.iex.exs&lt;/code&gt;&lt;/a&gt; file so that it&amp;#39;s applied automatically every time you open the shell.&lt;/p&gt;
&lt;h3&gt;Creating a Reusable Inspect Helper&lt;/h3&gt;
&lt;p&gt;Here&amp;#39;s a neat way to wrap &lt;code&gt;IO.inspect/2&lt;/code&gt; into your own helper module with preferred defaults. This way, you can keep consistent inspection output without repeating options everywhere:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Debug do
  @moduledoc &amp;quot;&amp;quot;&amp;quot;
  Convenience wrapper around `IO.inspect/2` with sensible defaults.
  &amp;quot;&amp;quot;&amp;quot;

  @default_opts [
    label: &amp;quot;DEBUG&amp;quot;,
    pretty: true,
    limit: :infinity,
    width: 120,
    syntax_colors: IO.ANSI.syntax_colors()
  ]

  @doc &amp;quot;&amp;quot;&amp;quot;
  Inspects a value with default debug options.

  This is pipe-friendly: it returns the given value unchanged
  after inspecting it.

  ## Examples

      iex&amp;gt; [1, 2, 3]
      ...&amp;gt; |&amp;gt; Enum.map(&amp;amp;(&amp;amp;1 * 2))
      ...&amp;gt; |&amp;gt; MyApp.Debug.inspect()
      [2, 4, 6]
  &amp;quot;&amp;quot;&amp;quot;
  def inspect(term, opts \\ []) do
    term
    |&amp;gt; IO.inspect(Keyword.merge(@default_opts, opts))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;result =
  users
  |&amp;gt; Enum.filter(&amp;amp;(&amp;amp;1.active?))
  |&amp;gt; MyApp.Debug.inspect(label: &amp;quot;Active users&amp;quot;)
  |&amp;gt; Enum.map(&amp;amp; &amp;amp;1.name)
  |&amp;gt; MyApp.Debug.inspect(label: &amp;quot;User names&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You get pretty printing (&lt;code&gt;pretty: true&lt;/code&gt;) by default.&lt;/li&gt;
&lt;li&gt;Lists and maps are not truncated (&lt;code&gt;limit: :infinity&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;A label is always shown (&lt;code&gt;DEBUG&lt;/code&gt; unless overridden).&lt;/li&gt;
&lt;li&gt;You can still override any option per call.&lt;/li&gt;
&lt;li&gt;It works fine when it&amp;#39;s in a pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Handy Visual Studio Code snippets&lt;/h1&gt;
&lt;p&gt;To make using &lt;code&gt;IO.inspect&lt;/code&gt; faster and more consistent, you can configure editor snippets in Visual Studio Code so you don&amp;#39;t have to type repetitive boilerplate each time.&lt;/p&gt;
&lt;p&gt;In Visual Studio Code, open: &lt;strong&gt;Code -&amp;gt; Settings… -&amp;gt; Configure Snippets -&amp;gt; Elixir&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Add the following snippet definitions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;inspect&amp;quot;: {
    &amp;quot;prefix&amp;quot;: &amp;quot;lin&amp;quot;,
    &amp;quot;body&amp;quot;: &amp;quot;IO.inspect($1, label: \&amp;quot;$1\&amp;quot;, pretty: true)&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;IO.inspect with label.&amp;quot;
  },
  &amp;quot;inspectSelectedText&amp;quot;: {
    &amp;quot;prefix&amp;quot;: &amp;quot;sin&amp;quot;,
    &amp;quot;body&amp;quot;: &amp;quot;IO.inspect($TM_SELECTED_TEXT, label: \&amp;quot;${TM_SELECTED_TEXT/(.*)/${1:/upcase}/}$0\&amp;quot;, pretty: true)&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;IO.inspect with selected text as label.&amp;quot;
  },
  &amp;quot;pipeInspect&amp;quot;: {
    &amp;quot;prefix&amp;quot;: &amp;quot;pin&amp;quot;,
    &amp;quot;body&amp;quot;: &amp;quot;|&amp;gt; IO.inspect(label: \&amp;quot;$1\&amp;quot;, pretty: true)&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;IO.inspect with pipe.&amp;quot;
  },
  &amp;quot;pipeInspectWithFileReference&amp;quot;: {
    &amp;quot;prefix&amp;quot;: &amp;quot;pinf&amp;quot;,
    &amp;quot;body&amp;quot;: &amp;quot;|&amp;gt; IO.inspect(label: \&amp;quot;$TM_FILEPATH:$TM_LINE_NUMBER$0\&amp;quot;, pretty: true)&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;IO.inspect with pipe and file reference.&amp;quot;
  },
  &amp;quot;inspectFromClipboard&amp;quot;: {
    &amp;quot;prefix&amp;quot;: &amp;quot;cin&amp;quot;,
    &amp;quot;body&amp;quot;: &amp;quot;IO.inspect($CLIPBOARD, label: \&amp;quot;${CLIPBOARD/(.*)/${1:/upcase}/}$0\&amp;quot;, pretty: true)&amp;quot;,
    &amp;quot;description&amp;quot;: &amp;quot;IO.inspect clipboard content.&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With these in place, you&amp;#39;ll have short prefixes to insert commonly used &lt;code&gt;IO.inspect/2&lt;/code&gt; patterns:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IO.inspect&lt;/code&gt; with label&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IO.inspect&lt;/code&gt; using selected text as label&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IO.inspect&lt;/code&gt; in a pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pinf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IO.inspect&lt;/code&gt; in a pipeline with file and line reference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cin&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IO.inspect&lt;/code&gt; clipboard content&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This way, you can quickly drop in debug output with consistent formatting, colors, and labels, without breaking your flow.&lt;/p&gt;
&lt;p&gt;Suppose you are transforming a list of user maps and want to check intermediate results inside a pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;users
|&amp;gt; Enum.filter(&amp;amp;(&amp;amp;1.active))
|&amp;gt; IO.inspect(label: &amp;quot;After filter&amp;quot;, pretty: true)
|&amp;gt; Enum.map(&amp;amp; &amp;amp;1.email)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the snippet defined above, you don&amp;#39;t have to type all that. Just type &lt;code&gt;pin&lt;/code&gt;, hit &lt;strong&gt;Tab&lt;/strong&gt;, and you get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;|&amp;gt; IO.inspect(label: &amp;quot;&amp;quot;, pretty: true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can immediately type your label (e.g., &lt;code&gt;&amp;quot;After filter&amp;quot;&lt;/code&gt;) and continue coding. This keeps your debugging consistent, colorful, and fast, without breaking your flow.&lt;/p&gt;
&lt;h2&gt;Best Practices&lt;/h2&gt;
&lt;p&gt;Now, let&amp;#39;s finally look at a few best practices when using &lt;code&gt;IO.inspect&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use labels liberally:&lt;/strong&gt; Unlabelled output is harder to parse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limit output:&lt;/strong&gt; Use &lt;code&gt;limit&lt;/code&gt; and &lt;code&gt;pretty&lt;/code&gt; for large collections.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoid leaving it in production&lt;/strong&gt; unless intentional.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wrap it&lt;/strong&gt; in helper functions when you want conditional control.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag concurrent output&lt;/strong&gt; with PIDs, timestamps, or request IDs.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/credo/overview.html&quot;&gt;&lt;strong&gt;Credo&lt;/strong&gt;&lt;/a&gt; can be used to detect unintentional calls to &lt;code&gt;IO.inspect&lt;/code&gt; in a CI/CD pipeline.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;IO.inspect&lt;/code&gt; may look like a humble debugging tool, but in Elixir, it&amp;#39;s a powerful way to see what&amp;#39;s going on without breaking your code&amp;#39;s flow. By combining it with labels, formatting, conditional output, and process context, you can get precise insights into your program&amp;#39;s behavior, all without leaving your editor.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Structs and Embedded Schemas in Elixir: Beyond Maps</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/09/09/structs-and-embedded-schemas-in-elixir-beyond-maps.html"/>
    <id>https://blog.appsignal.com/2025/09/09/structs-and-embedded-schemas-in-elixir-beyond-maps.html</id>
    <published>2025-09-09T00:00:00+00:00</published>
    <updated>2025-09-09T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s dive into the ins and outs of structs and Ecto schemas.</summary>
    <content type="html">&lt;p&gt;If you work with Elixir, chances are you&amp;#39;ve used structs plenty of times and are likely aware of Ecto schema.&lt;/p&gt;
&lt;p&gt;However, you may not have explored structs in depth or used Ecto schemas beyond the database context.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll explore the ins and outs of structs and Ecto schemas.&lt;/p&gt;
&lt;h2&gt;What is a Struct?&lt;/h2&gt;
&lt;p&gt;Visually, a struct is the closest thing Elixir has to a class.
Functionally, it&amp;#39;s a named map with some extra features.
You&amp;#39;d typically use it in place of a map when your code might benefit from those extra features.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/v1.18.4/lib/elixir/lib/kernel/utils.ex#L103&quot;&gt;&lt;code&gt;defstruct&lt;/code&gt; macro in &lt;code&gt;Kernel.Utils&lt;/code&gt;&lt;/a&gt;
is fairly large, but mostly understandable.&lt;/p&gt;
&lt;p&gt;Generally, a struct relies on some built-in Elixir features to enhance a map by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stopping you from calling &lt;code&gt;defstruct&lt;/code&gt; in the same module twice&lt;/li&gt;
&lt;li&gt;Setting up a layer of checks to ensure you only access and use specific keys in a struct&lt;/li&gt;
&lt;li&gt;Setting up optional key enforcement&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these features use &lt;code&gt;:ets&lt;/code&gt;, Erlang’s in-memory table system (which warrants its own article).&lt;/p&gt;
&lt;p&gt;So eventually, you end up with an &lt;code&gt;:ets&lt;/code&gt;-powered map that has a few extra hidden keys and special features.
These features make structs a bit stricter, better defined, and, in some ways, more powerful than plain maps.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see how structs work in practice.&lt;/p&gt;
&lt;h2&gt;What Happens Behind the Scenes with Structs in Elixir?&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s start by defining a struct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule User do
  defstruct [:name, :email, :age]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that small bit of code, we&amp;#39;ve declared a special kind of map. Where a regular map would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;map_user = %{name: &amp;quot;John&amp;quot;, email: &amp;quot;john@example.com&amp;quot;, age: 30}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A struct is declared like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;user = %User{name: &amp;quot;John&amp;quot;, email: &amp;quot;john@example.com&amp;quot;, age: 30}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the hood, the struct is still a map, but has an extra key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Map.keys(user)

[:name, :__struct__, :email, :age]

iex&amp;gt; user.__struct__

User
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;__struct__&lt;/code&gt; field is automatically added and helps Elixir distinguish between regular maps and structs.&lt;/p&gt;
&lt;p&gt;Structs can have strict or required keys: let&amp;#39;s look at those next.&lt;/p&gt;
&lt;h2&gt;Structs Have Strict Keys&lt;/h2&gt;
&lt;p&gt;Structs provide compile-time guarantees about which keys are valid.&lt;/p&gt;
&lt;p&gt;This works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%User{name: &amp;quot;John&amp;quot;, email: &amp;quot;john@example.com&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this raises an error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%User{name: &amp;quot;John&amp;quot;, foo: &amp;quot;value&amp;quot;}

** (KeyError) key :foo not found
    expanding struct: User.__struct__/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Accessing a value through a key actually works in the same way as with maps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;user.foo

# ** (KeyError) key :foo not found in: %User{name: &amp;quot;John&amp;quot;, email: &amp;quot;john@example.com&amp;quot;, age: 30}

map_user.foo

# ** (KeyError) key :foo not found in: %{name: &amp;quot;John&amp;quot;, age: 30, email: &amp;quot;john@example.com&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Accessing using &lt;code&gt;[]&lt;/code&gt;, however, is very different:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;map_user[:foo]

# nil

user[:foo]

# ** (UndefinedFunctionError) function User.fetch/2 is undefined (User does not implement the Access behavior
# You can use the &amp;quot;struct.field&amp;quot; syntax to access struct fields. You can also use Access.key!/1 to access struct fields dynamically inside get_in/put_in/update_in). Make sure the module name is correct and has been specified in full (or that an alias has been defined)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So using &lt;code&gt;Access&lt;/code&gt; behavior doesn’t add extra enforcement. Accessing an invalid key fails simply because
structs don’t implement the &lt;code&gt;Access&lt;/code&gt; protocol.&lt;/p&gt;
&lt;p&gt;Matching now works like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%{foo: foo} = user

# ** (MatchError) no match of right hand side value:
#    %User{name: &amp;quot;John&amp;quot;, email: &amp;quot;john@example.com&amp;quot;, age: 30}

%{foo: foo} = map_user

# ** (MatchError) no match of right hand side value:
#    %{name: &amp;quot;John&amp;quot;, age: 30, email: &amp;quot;john@example.com&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So it works mostly in the same way, but there is a slight difference if you include the struct name in the
match (which we will get to).&lt;/p&gt;
&lt;h2&gt;Structs Can Have Required Keys&lt;/h2&gt;
&lt;p&gt;You can also enforce required keys. If we define our struct like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule User do
  @enforce_keys [:email]
  defstruct name: nil, email: nil, age: nil
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is possible:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;user = %User{email: &amp;quot;john@example.com&amp;quot;}
user = %User{email: &amp;quot;john@example.com&amp;quot;, age: 25}
user = %User{email: &amp;quot;john@example.com&amp;quot;, name: &amp;quot;John&amp;quot;}
user = %User{email: &amp;quot;john@example.com&amp;quot;, name: &amp;quot;John&amp;quot;, age: 25}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But not giving an email when creating a struct raises an error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;user = %User{age: 30}

# ** (ArgumentError) the following keys must also be given when building struct User: [:email]
#     expanding struct: User.__struct__/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s a bit of extra strictness you can give your struct for various use cases.&lt;/p&gt;
&lt;h2&gt;Structs Can Have Initial Values&lt;/h2&gt;
&lt;p&gt;This doesn&amp;#39;t have a wide application, but can be useful for a bunch of stuff (for example,
when you&amp;#39;re using structs to power configuration options):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule User do
  defstruct [name: nil, email: nil, age: 20]
end

%User{}
# User{name: nil, email: nil, age: 20}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also acts as the basis for Ecto schemas.&lt;/p&gt;
&lt;h2&gt;Structs Can Be Pattern-matched in Function Clauses&lt;/h2&gt;
&lt;p&gt;Structs enable a bit of extra pattern matching that goes beyond what maps offer.
Here, we define a few basic function clauses for our user struct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def process_user(%User{age: age}) when age &amp;gt;= 18 do
  &amp;quot;Adult user&amp;quot;
end

def process_user(%User{age: age}) when age &amp;lt; 18 do
  &amp;quot;Minor user&amp;quot;
end

def process_user(%User{name: name, email: email}) do
  &amp;quot;User #{name} with email #{email}&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The compiler can statically verify that you&amp;#39;re matching on valid struct fields,
catching typos and invalid keys at compile time.&lt;/p&gt;
&lt;p&gt;You can&amp;#39;t just call &lt;code&gt;process_user/1&lt;/code&gt; with any map that has &lt;code&gt;:name&lt;/code&gt;, &lt;code&gt;:email&lt;/code&gt;, or &lt;code&gt;:age&lt;/code&gt; keys.
It has to be the &lt;code&gt;User&lt;/code&gt; struct.
Not some random map, not some random other struct, specifically the user struct.&lt;/p&gt;
&lt;p&gt;Really, the &lt;code&gt;User&lt;/code&gt; part of &lt;code&gt;%User{...}&lt;/code&gt; is a form of pattern matching. It means that it&amp;#39;s a map,
that has the &lt;code&gt;__struct__&lt;/code&gt; key, the value of which is &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That means you can do more with it.&lt;/p&gt;
&lt;p&gt;The following clause accepts a &lt;code&gt;%User{}&lt;/code&gt; and a &lt;code&gt;%PowerUser{}&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def process_user(%m{name: name} = user) when m in [User, PowerUser] do
  &amp;quot;User #{name} is a #{m}&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;And the following accepts any struct, but not regular maps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def process_user(%_{name: name} = user) do
  &amp;quot;User #{name} is a #{m}&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that matching in function clauses follows the same rules with structs as anywhere else.
You can&amp;#39;t specify keys that the struct doesn&amp;#39;t define.&lt;/p&gt;
&lt;p&gt;This wouldn&amp;#39;t work, and would raise a &lt;code&gt;CompileError&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def process_user(%User{foo: foo}), do: nil
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Structs Can Have Dialyzer Types Declared&lt;/h2&gt;
&lt;p&gt;If your project uses Dialyzer, a common pattern (as suggested in the official documentation)
is to declare a type &lt;code&gt;t&lt;/code&gt; within the struct module.&lt;/p&gt;
&lt;p&gt;In our example, we get &lt;code&gt;User.t()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule User do
  defstruct [:name, :email, :age]

  @type t :: %__MODULE__{
    name: String.t() | nil,
    email: String.t() | nil,
    age: non_neg_integer() | nil
  }
end

@spec create_user(String.t(), String.t(), non_neg_integer()) :: User.t()
def create_user(name, email, age) do
  %User{name: name, email: email, age: age}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dialyzer can use these type specifications to catch type mismatches and provide better static analysis.&lt;/p&gt;
&lt;p&gt;With the advent of actual types in elixir, this is slowly getting phased out.
Once we have real type declarations, Dialyzer typespecs will probably get replaced.
For now, though, it&amp;#39;s a useful pattern to follow.&lt;/p&gt;
&lt;h2&gt;Structs Are Stricter, More Powerful Maps&lt;/h2&gt;
&lt;p&gt;For a bit of extra boilerplate, structs give you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;More power&lt;/strong&gt;: Compile-time validation, enforced keys, and better pattern matching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extra checks&lt;/strong&gt;: Static analysis of field names and types.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clarity and self-documentation&lt;/strong&gt;: Clear contracts about data shape.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let&amp;#39;s move on to look at schemas.&lt;/p&gt;
&lt;h2&gt;What is an Embedded Schema?&lt;/h2&gt;
&lt;p&gt;There are two types of Ecto schemas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Regular schemas&lt;/strong&gt; are backed by a database table or view, and used to map database tables to Elixir code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embedded schemas&lt;/strong&gt; are not directly associated to a database table and were originally intended to power &lt;code&gt;jsonb&lt;/code&gt;
columns in databases using &lt;code&gt;embeds_one&lt;/code&gt;, &lt;code&gt;embeds_many&lt;/code&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Very obviously, both were originally intended to power Ecto and work with database tables.&lt;/p&gt;
&lt;p&gt;With the split of &lt;code&gt;ecto&lt;/code&gt; and &lt;code&gt;ecto_sql&lt;/code&gt;, embedded schemas started to get used for much more.&lt;/p&gt;
&lt;h3&gt;Embedded Schemas Behind the Scenes&lt;/h3&gt;
&lt;p&gt;An embedded schema is essentially a struct with additional Ecto functionality. Here&amp;#39;s how you declare one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Address do
  use Ecto.Schema

  embedded_schema do
    field :street, :string
    field :city, :string
    field :postal_code, :string
    field :country, :string, default: &amp;quot;US&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a struct similar to what we saw before, but with Ecto&amp;#39;s schema capabilities layered on top.&lt;/p&gt;
&lt;p&gt;What actually happens is not a huge amount, but a bit more than what we get with just structs.&lt;/p&gt;
&lt;p&gt;The line &lt;code&gt;use Ecto.Schema&lt;/code&gt; first calls the &lt;a href=&quot;https://github.com/elixir-ecto/ecto/blob/v3.13.2/lib/ecto/schema.ex#L513&quot;&gt;&lt;code&gt;__using__&lt;/code&gt;&lt;/a&gt; macro, which registers a bunch of accumulating module attributes that the subsequent steps will use.&lt;/p&gt;
&lt;p&gt;A module attribute is a named value you can use to store data within a module. Here&amp;#39;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyModule do
  @foo &amp;quot;bar&amp;quot;
  def get_foo, do: @foo

  @foo &amp;quot;baz&amp;quot;
  def get_foo_also, do: @foo
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;get_foo()&lt;/code&gt; will return &lt;code&gt;&amp;quot;bar&amp;quot;&lt;/code&gt;, while &lt;code&gt;get_foo_also()&lt;/code&gt; returns &lt;code&gt;&amp;quot;baz&amp;quot;&lt;/code&gt;.
However, if you set the attribute to accumulate, using this line in the same module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Module.register_attribute(__MODULE__, :foo, accumulate: true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then extra values set to the attribute will no longer replace the old value, but rather append to a list.
So &lt;code&gt;get_foo_also()&lt;/code&gt; in the same example will return &lt;code&gt;[&amp;quot;bar&amp;quot;, &amp;quot;baz&amp;quot;]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Eleven such attributes in total are registered, their intent being to hold the schema definition:
fields, associations, primary keys, etc. This is then used by the &lt;code&gt;embedded_schema&lt;/code&gt; macro.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;embedded_schema&lt;/code&gt; macro simply calls the &lt;code&gt;schema&lt;/code&gt; macro with the &lt;code&gt;source&lt;/code&gt; argument set to &lt;code&gt;nil&lt;/code&gt;. So instead of:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;embedded_schema do
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could actually just do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;schema nil do
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Really, the macros do exactly the same thing, other than not have a source.&lt;/p&gt;
&lt;p&gt;When defining a schema using either of these macros, the following happens:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A bit of code is injected into the module to import the various helpers we need, such as &lt;code&gt;field&lt;/code&gt;, &lt;code&gt;embeds_one&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;The block we pass into the macro contains calls to the above helpers. This code now runs and puts values
into the accumulating attributes registered, storing all the schema information we specified for later use.&lt;/li&gt;
&lt;li&gt;The module now contains all the schema information within its attributes. The &lt;code&gt;Ecto.Schema.__schema__/1&lt;/code&gt; function is
called, and the module is passed in as an argument. This gives us a tuple containing all of our struct&amp;#39;s fields and something called &lt;code&gt;bags_of_clauses&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defstruct&lt;/code&gt; is called with the list of struct fields, defining a plain struct.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__changeset__&lt;/code&gt; and &lt;code&gt;__schema__&lt;/code&gt; functions are defined on the module. The &lt;code&gt;__changeset__&lt;/code&gt; function is what allows our
schema struct to be used with &lt;code&gt;Ecto&lt;/code&gt; changesets, and the &lt;strong&gt;schema&lt;/strong&gt; function provides introspection for us as well as for
usage with &lt;code&gt;Ecto.Query&lt;/code&gt;. The &lt;code&gt;bags_of_clauses&lt;/code&gt; value defines a few of the clauses
for the &lt;code&gt;__schema__&lt;/code&gt; function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our &lt;code&gt;Address&lt;/code&gt; embedded schema effectively becomes this struct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defstruct [street: nil, city: nil, postal_code: nil, country: &amp;quot;US&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;@enforce_keys&lt;/code&gt; is not set, but you could still set it if you add it right before the call to &lt;code&gt;embedded_schema&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, effectively, &lt;code&gt;embedded_schema&lt;/code&gt; creates a struct, but with extra features that make it work with &lt;code&gt;Ecto&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Changesets and Validation&lt;/h3&gt;
&lt;p&gt;Embedded schemas shine when combined with changesets:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Address do
  use Ecto.Schema

  embedded_schema do
    field :street, :string
    field :city, :string
    field :postal_code, :string
    field :country, :string, default: &amp;quot;US&amp;quot;
  end

  def changeset(address, attrs) do
    address
    |&amp;gt; cast(attrs, [:street, :city, :postal_code, :country])
    |&amp;gt; validate_required([:street, :city, :postal_code])
    |&amp;gt; validate_format(:postal_code, ~r/^\d{5}(-\d{4})?$/)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This provides type enforcement, format validation, and required field checks.
Your changeset will check that all the required fields have a value, validate the format of the postcode, and will mark itself as invalid if anything is invalid.&lt;/p&gt;
&lt;p&gt;This is clearly originally intended for databases, but because the embedded schema doesn&amp;#39;t need a backing table,
it can be used for much more.&lt;/p&gt;
&lt;h3&gt;API Input Prevalidation and the Command Pattern&lt;/h3&gt;
&lt;p&gt;Embedded schemas with changesets provide a cheap way to parse and sanitize API input.
I usually call these special embedded schemas &amp;quot;commands&amp;quot;, in that they &lt;em&gt;command&lt;/em&gt; our business logic to do something.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CreateUserCommand do
  use Ecto.Schema

  alias Ecto.Changeset

  embedded_schema do
    field :name, :string
    field :email, :string
    field :age, :integer
  end

  def changeset(params) do
    %__MODULE__{}
    |&amp;gt; cast(params, [:name, :email, :age])
    |&amp;gt; validate_required([:name, :email])
    |&amp;gt; validate_format(:email, ~r/@/)
    |&amp;gt; validate_number(:age, greater_than: 0)
  end

  def validate(params) do
    case changeset(params) do
      %Changeset{valid?: true} = changeset -&amp;gt;
        {:ok, Changeset.apply_changes(changeset)}
      %Changeset{valid?: false} = changeset -&amp;gt;
        {:error, changeset}
    end
  end
end


defmodule UserController do
  def create(conn, %{&amp;quot;user&amp;quot; =&amp;gt; user_params}) do
    with {:ok, command} &amp;lt;-  CreateUserCommand.validate(user_params) do
      UserService.create_user(command)
      send_resp(conn, 200)
      # the FallbackController handles the error response
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is something you would generally use for checks and parameter sanitization that don&amp;#39;t need access to the database (which tends to be true for most of the checks you would want to do.)&lt;/p&gt;
&lt;p&gt;For example, when creating a user, you might need to check that the email is unique, that any associated
foreign keys exist in the database, or that a number is greater than another number in the database. Those all need a database check.&lt;/p&gt;
&lt;p&gt;But there are things you can use an embedded schema for, to prevalidate the insert by just checking and
parsing the params, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The email being a string and of a valid format&lt;/li&gt;
&lt;li&gt;The first name being provided&lt;/li&gt;
&lt;li&gt;Age being a number between 18 and 30&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically, anything that enforces basic constraints and rules you know the input should obey.&lt;/p&gt;
&lt;p&gt;That way, you can do a fast and cheap validation, reject the request if it doesn&amp;#39;t pass, and avoid wasting resources
by doing all the necessary validations at once (both cheap and expensive ones). This enables a &lt;em&gt;fail fast&lt;/em&gt; approach in your API.&lt;/p&gt;
&lt;p&gt;The added bonus of this pattern is that if your changeset is valid, you can use &lt;code&gt;Changeset.apply_changes/1&lt;/code&gt;
to get the &lt;code&gt;CreateUserCommand&lt;/code&gt; struct with all of the data set, ready to be passed into the deeper business logic.&lt;/p&gt;
&lt;p&gt;So instead of one big complex thing, you get two simpler things, and the more important,
more expensive one can now be reused in other places (like, for example, in your LiveView admin dashboard).&lt;/p&gt;
&lt;h3&gt;Powering Forms in Live (and Dead) Views&lt;/h3&gt;
&lt;p&gt;LiveView already &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/form-bindings.html&quot;&gt;promotes using &lt;code&gt;%Form{}&lt;/code&gt; structs&lt;/a&gt;
to power forms. These structs are basically wrappers around changesets.
Converting a changeset to a form is as simple as calling &lt;code&gt;Phoenix.Component.to_form(changeset)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So understanding that the schemas powering those changesets don&amp;#39;t need to be tied to a table unlocks
a lot you could do.&lt;/p&gt;
&lt;p&gt;Say you have a LiveView page with a list of users, and a form to add a new user.
You can create a changeset for that form as early on as in your &lt;code&gt;mount&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def mount(_params, _session, socket) do
  changeset = CreateUserCommand.changeset(%{})
  {:ok, assign(socket, changeset: changeset)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you render the form passing in &lt;code&gt;to_form(@changeset)&lt;/code&gt;, binding change and submit events.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def user_form(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;.form
    for={to_form(@changeset)}
    :let={f}
    phx-change=&amp;quot;validate&amp;quot;
    phx-submit=&amp;quot;create&amp;quot;
  &amp;gt;
    &amp;lt;.input type=&amp;quot;text&amp;quot; :field={f[:name]} /&amp;gt;
    &amp;lt;.input type=&amp;quot;email&amp;quot; :field={f[:email]} /&amp;gt;
    &amp;lt;.input type=&amp;quot;number&amp;quot; :field={f[:number]} /&amp;gt;
  &amp;lt;/.form&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn&amp;#39;t really new. We&amp;#39;ve used changesets to power forms since before LiveView, but the key point is that the schema
powering the changeset doesn&amp;#39;t need to be tied to a database.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(&amp;quot;validate&amp;quot;, %{&amp;quot;user&amp;quot; =&amp;gt; params}, socket) do
  changeset =
    params
    |&amp;gt; CreateUserCommand.changeset()
    |&amp;gt; Map.put(:action, :validated)  # This makes errors visible

  {:noreply, assign(socket, changeset: changeset)}
end

def handle_event(&amp;quot;create&amp;quot;, %{&amp;quot;user&amp;quot; =&amp;gt; params}, socket) do
  case CreateUserCommand.validate(params) do
    {:ok, command} -&amp;gt;
      # this is live view. we expect it will work as the form is correctly setup and prevalidation worked
      # if it fails, let it crash, elixir style!
      {:ok, user} = UserService.create_user(command)
      {:noreply, put_flash(socket, &amp;quot;User created!&amp;quot;)}
    {:error, changeset} -&amp;gt;
      {:noreply, assign(socket, changeset: Map.put(changeset, :action, :validated)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, we&amp;#39;ve reused our &lt;code&gt;CreateUserCommand&lt;/code&gt;, so that our API and LiveView share roughly two-thirds of the code.&lt;/p&gt;
&lt;p&gt;If the command doesn&amp;#39;t suit your form, you can always define a custom embedded schema module right in your LiveView,
or even use &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#module-schemaless-changesets&quot;&gt;schemaless changesets&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The same principle applies. The only difference with schemaless changesets is that we need to give them a name when
converting them to a form using &lt;code&gt;to_form(changeset, as: :my_name)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Validation errors aren&amp;#39;t visible until the changeset&amp;#39;s &lt;code&gt;:action&lt;/code&gt; field is something other than &lt;code&gt;nil&lt;/code&gt;.
When &lt;code&gt;Repo.insert(changeset)&lt;/code&gt; or &lt;code&gt;Repo.update(changeset)&lt;/code&gt; get called, the returning invalid changeset
in &lt;code&gt;{:error, changeset}&lt;/code&gt; has the action field set to insert or update, respectively.&lt;/p&gt;
&lt;p&gt;This never happens with changesets based on embedded schemas, so you need to set the action manually using &lt;code&gt;Map.put&lt;/code&gt;, for example.&lt;/p&gt;
&lt;h2&gt;A Word of Caution About Elixir Packages &lt;code&gt;typed_struct&lt;/code&gt; and &lt;code&gt;domo&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://hex.pm/packages/typed_struct&quot;&gt;&lt;code&gt;typed_struct&lt;/code&gt;&lt;/a&gt; package eliminates some boilerplate by automatically
generating type specifications:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule User do
  use TypedStruct

  typedstruct do
    field :name, String.t()
    field :email, String.t()
    field :age, non_neg_integer()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is effectively the same as declaring a &lt;code&gt;User&lt;/code&gt; struct using &lt;code&gt;defstruct&lt;/code&gt;,
enforcing all keys and declaring a &lt;code&gt;User.t()&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;However, this package hasn&amp;#39;t been receiving updates recently, which is a concern for long-term maintenance.
Plus, with the advent of Elixir types, its usefulness is likely to decrease.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://hexdocs.pm/domo/Domo.html&quot;&gt;&lt;code&gt;domo&lt;/code&gt;&lt;/a&gt; package builds on top of typed structs by generating utility
functions, such as &lt;code&gt;new&lt;/code&gt; and &lt;code&gt;new!&lt;/code&gt;. But, in my experience, it also adds a significant compilation time overhead.&lt;/p&gt;
&lt;p&gt;At &lt;a href=&quot;https://www.v7labs.com/&quot;&gt;V7&lt;/a&gt;, we&amp;#39;ve been using these extensively, and they&amp;#39;ve proven useful.&lt;/p&gt;
&lt;p&gt;They&amp;#39;ve also proven to increase our compilation time significantly,
and &lt;code&gt;domo&lt;/code&gt; seems to regularly cause compilation deadlocks, so we&amp;#39;re seriously considering removing them.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s finally take a quick look at future Elixir types before wrapping up.&lt;/p&gt;
&lt;h2&gt;Future Elixir Types&lt;/h2&gt;
&lt;p&gt;With the growth of the Elixir type system, structs are becoming safer and safer. The compiler is inferring more and
catching more bugs.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re likely approaching a point where it becomes questionable whether we should use Dialyzer, for example.&lt;/p&gt;
&lt;p&gt;The way I see it, Dialyzer is as useful as ever, and whatever type of improvements we get in the background are free and
do not conflict with it at all. If anything, they might reveal where we can improve our type specs.&lt;/p&gt;
&lt;p&gt;Once Elixir type specifications become available, we will probably be replacing type specs with those, and
hopefully, that will be an easy migration.&lt;/p&gt;
&lt;p&gt;In the meantime, we should lean into things that already benefit from the type system and offer the best of both worlds.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we ran through some use cases for Elixir structs and schemas.&lt;/p&gt;
&lt;p&gt;Hopefully, you now have a deeper understanding of structs, even if you were already comfortable using them.&lt;/p&gt;
&lt;p&gt;As for embedded schemas, maybe you&amp;#39;ve found a new use case for them.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Tracking Errors in Absinthe for Elixir with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/08/19/tracking-errors-in-absinthe-for-elixir-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2025/08/19/tracking-errors-in-absinthe-for-elixir-with-appsignal.html</id>
    <published>2025-08-19T00:00:00+00:00</published>
    <updated>2025-08-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn how to use AppSignal to monitor, debug, and resolve errors in your Absinthe-based GraphQL API.</summary>
    <content type="html">&lt;p&gt;GraphQL provides a powerful approach to building APIs, and Absinthe is the leading GraphQL implementation for Elixir applications. While GraphQL offers many benefits, it can introduce a set of errors and performance bottlenecks that might be challenging to track and debug.&lt;/p&gt;
&lt;p&gt;In this article, you’ll learn how to use AppSignal to monitor, debug, and resolve errors in your Absinthe-based GraphQL API.&lt;/p&gt;
&lt;p&gt;To follow along with the tutorial, you&amp;#39;ll need a few things in place.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;An AppSignal account — you can &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;sign up for a free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Some experience working with Elixir and the Phoenix framework.&lt;/li&gt;
&lt;li&gt;A local installation of Elixir, the Phoenix framework, and PostgreSQL. &lt;a href=&quot;https://hexdocs.pm/phoenix/up_and_running.html&quot;&gt;Follow this guide&lt;/a&gt; to get your local environment set up.&lt;/li&gt;
&lt;li&gt;An Elixir app with Absinthe integrated. If you don&amp;#39;t have one ready, &lt;a href=&quot;https://github.com/iamaestimo/absinthe-graphql-playground-app&quot;&gt;fork the example app we&amp;#39;ll be using for this tutorial&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Introducing Our Example Phoenix App&lt;/h2&gt;
&lt;p&gt;Our example application is a Phoenix app that models a simple sports league management system with leagues, seasons, teams, and players. The API is accessible via a GraphQL endpoint at &lt;code&gt;/wendigo/api/graphql&lt;/code&gt;, and a GraphiQL interface at &lt;code&gt;/wendigo/api/graphiql&lt;/code&gt; (a nifty web interface for testing the API in development).&lt;/p&gt;
&lt;p&gt;Going through a step-by-step project build would make this tutorial too long. So, from here onwards, we&amp;#39;ll be referencing our pre-built example app, which already has Absinthe integrated. For more information on integrating Absinthe into a new Phoenix application, &lt;a href=&quot;https://hexdocs.pm/absinthe/plug-phoenix.html&quot;&gt;see the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s add the AppSignal mix package.&lt;/p&gt;
&lt;h3&gt;Adding the AppSignal Package&lt;/h3&gt;
&lt;p&gt;Open up the &lt;code&gt;mix.exs&lt;/code&gt; file and add the main AppSignal package, as well as the AppSignal Phoenix package (required for Phoenix apps):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs

...
defp deps do
  [
    ...
    {:appsignal, &amp;quot;~&amp;gt; 2.8&amp;quot;},
    {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
    ...
  ]
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now run &lt;code&gt;mix deps.get&lt;/code&gt; to fetch the newly added dependencies.&lt;/p&gt;
&lt;h3&gt;Installing and Configuring AppSignal&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;mix appsignal.install YOUR_PUSH_API_KEY&lt;/code&gt; to install AppSignal, then go through the configuration options that will be presented to you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name your app: Give your app a suitable name.&lt;/li&gt;
&lt;li&gt;The configuration method to be used: Here, you have a choice between using an environment variable or using a config file. I recommend using the configuration file, as it provides more flexibility later on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&amp;#39;re done with the configuration, you&amp;#39;ll see an output similar to the one below, which means you&amp;#39;ve successfully configured AppSignal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Welcome to AppSignal!

This installer will guide you through setting up AppSignal in your application.
We will perform some checks on your system and ask how you like AppSignal to be
configured.

================================================================================


Validating Push API key: Valid! 🎉
What is your application&amp;#39;s name? [wendigo]: wendigo_app

There are two methods of configuring AppSignal in your application.
  Option 1: Using a &amp;quot;config/appsignal.exs&amp;quot; file. (1)
  Option 2: Using system environment variables.  (2)

What is your preferred configuration method? [1]: 1
Writing config file config/appsignal.exs: Success!
Linking config to config/config.exs: Success!
Activating dev environment: Success!
Activating prod environment: Success!

AppSignal detected a Phoenix app
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that&amp;#39;s done, the app should start sending data over to the AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-08/initial-appsignal-dashboard.png&quot; alt=&quot;Initial AppSignal Dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Before moving into the actual implementation of error tracking in Absinthe, it&amp;#39;s very important that we learn what GraphQL is all about, and especially how it works. This will help us understand where errors could come from and give us a basis for setting up effective error tracking.&lt;/p&gt;
&lt;h2&gt;What Is GraphQL?&lt;/h2&gt;
&lt;p&gt;Nowadays, building applications often involves providing API access points. REST APIs are often used as the solution for serving data to clients, but creating a REST API that meets all user requirements can be challenging, especially as applications grow in complexity.&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s where &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt; comes in. Unlike REST, GraphQL empowers clients to request the exact data they need.&lt;/p&gt;
&lt;p&gt;We won&amp;#39;t go into the details of how GraphQL actually works; instead, we&amp;#39;ll focus on the GraphQL schema since it&amp;#39;s the interface concerned with processing GraphQL requests. Later in this article, we&amp;#39;ll learn how errors occur and how to resolve them using AppSignal.&lt;/p&gt;
&lt;h2&gt;The GraphQL Schema&lt;/h2&gt;
&lt;p&gt;The GraphQL schema is a blueprint of the entire API. It helps us define the domain model and how the server will respond to requests for data.&lt;/p&gt;
&lt;p&gt;Below is summarized code showing the example application schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#lib/wendigo_web/graphql/schema.ex

defmodule WendigoWeb.GraphQL.Schema do
  use Absinthe.Schema

  alias Wendigo.Context.{Leagues, Players, Seasons, Teams}
  alias WendigoWeb.Resolvers.{LeagueResolver, PlayerResolver, SeasonResolver, TeamResolver}

  import_types(Absinthe.Type.Custom)
  import_types(WendigoWeb.GraphQL.Types)

  query do
    @desc &amp;quot;Get a league&amp;quot;
    field :league, :league do
      arg(:id, non_null(:id))
      resolve(&amp;amp;LeagueResolver.get_league/3)
    end

    @desc &amp;quot;List leagues&amp;quot;
    field :leagues, list_of(:league) do
      arg(:first, :integer)
      arg(:offset, :integer)
      resolve(&amp;amp;LeagueResolver.list_leagues/3)
    end

    ...
  end

  mutation do
    @desc &amp;quot;Create a season&amp;quot;
    field :create_season, :season do
      arg(:name, non_null(:string))
      arg(:start_date, non_null(:date))
      arg(:end_date, non_null(:date))
      resolve(&amp;amp;SeasonResolver.create_season/3)
    end
    ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The schema is made up of several key components: types, queries, and mutations.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Types&lt;/h3&gt;
&lt;p&gt;Types describe the shape of the data objects. Types can be used directly in the schema or imported from elsewhere to keep the schema clean and organized.&lt;/p&gt;
&lt;p&gt;The code below shows the &lt;code&gt;league&lt;/code&gt; object type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/wendigo/schema/league.ex

defmodule Wendigo.Schema.League do
  @moduledoc &amp;quot;&amp;quot;&amp;quot;
  Schema for the `leagues` table.
  &amp;quot;&amp;quot;&amp;quot;
  use Ecto.Schema
  import Ecto.Changeset

  @type t() :: %__MODULE__{}

  @primary_key {:id, :string, autogenerate: {Ecto.Nanoid, :autogenerate, []}}
  schema &amp;quot;leagues&amp;quot; do
    field :name, :string
    field :level, :string
    timestamps()
  end

  @doc &amp;quot;Creates a changeset for a league&amp;quot;
  def changeset(struct, params) do
    struct
    |&amp;gt; cast(params, [:name, :level])
    |&amp;gt; validate_required([:name])
    |&amp;gt; validate_length(:name, max: 100)
    |&amp;gt; validate_length(:level, max: 100)
  end

  def changeset(params),
    do: changeset(%__MODULE__{}, params)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Queries&lt;/h3&gt;
&lt;p&gt;These are read-only operations that fetch data.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...
query do
  @desc &amp;quot;Get a league&amp;quot;
  field :league, :league do
    arg(:id, non_null(:id))
    resolve(&amp;amp;LeagueResolver.get_league/3)
  end
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Mutations&lt;/h3&gt;
&lt;p&gt;Mutations are operations that modify data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...

mutation do
  @desc &amp;quot;Create a season&amp;quot;
  field :create_season, :season do
    arg(:name, non_null(:string))
    arg(:start_date, non_null(:date))
    arg(:end_date, non_null(:date))
    resolve(&amp;amp;SeasonResolver.create_season/3)
  end
  ...
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the information we have so far, let&amp;#39;s now explore some of the errors you might encounter when working with Absinthe and how you can use AppSignal to track them.&lt;/p&gt;
&lt;h2&gt;Absinthe Errors&lt;/h2&gt;
&lt;p&gt;There are many error types that can affect a GraphQL API, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Schema validation errors&lt;/strong&gt; - These happen when the query doesn&amp;#39;t conform to the rules defined in the schema (for example, requesting a field that doesn&amp;#39;t exist in the schema):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  user(id: &amp;quot;123&amp;quot;) {
    nonexistentField
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Query syntax errors&lt;/strong&gt; happen when a client sends a malformed query, (for example, an incorrect query syntax, as shown below):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  user(id: &amp;quot;123&amp;quot; { # Missing closing parenthesis
    name
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resolver errors&lt;/strong&gt; can occur when a resolver fails to fetch data for one reason or another. (For example, failing to find a record or mishandling &lt;code&gt;nil&lt;/code&gt; values):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;resolve fn %{id: id}, _ -&amp;gt;
  case Repo.get(User, id) do
    nil -&amp;gt; {:error, &amp;quot;User not found&amp;quot;}
    user -&amp;gt; {:ok, user}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Type mismatch errors&lt;/strong&gt; occur when the data returned by a resolver fails to match what is defined by the schema. A good example is returning a string instead of an integer:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;field :age, :integer do
  resolve fn _, _ -&amp;gt; {:ok, &amp;quot;twenty three&amp;quot;} end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity limit errors:&lt;/strong&gt; Absinthe allows you to set up limits on the number of levels when deep nesting a query. As such, should a request exceed the set limits, a complexity limit error occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;{
  users {
    orders {
      items {
        product {
          supplier {
            contact {
              phone
            }
          }
        }
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These aren&amp;#39;t the only errors you can expect; there are others like authentication (and authorization) errors, and argument validation errors. You can get more information about them from the &lt;a href=&quot;https://graphql.org/learn/response/#errors&quot;&gt;GraphQL error documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that you know the types of errors to expect, let&amp;#39;s see how we can use AppSignal to handle a few of them.&lt;/p&gt;
&lt;h2&gt;Tracking Absinthe Errors Using AppSignal&lt;/h2&gt;
&lt;p&gt;By default, &lt;a href=&quot;https://www.appsignal.com/elixir/absinthe-monitoring&quot;&gt;AppSignal will automatically instrument Absinthe requests&lt;/a&gt;, as you can see below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-08/automatic-absinthe-tracking.png&quot; alt=&quot;Automatic Absinthe Tracking&quot;/&gt;&lt;/p&gt;
&lt;p&gt;However, for Absinthe-specific errors, you&amp;#39;ll need an extra setup to effectively surface these errors to the AppSignal dashboard.&lt;/p&gt;
&lt;h2&gt;How Absinthe Treats Errors&lt;/h2&gt;
&lt;p&gt;Absinthe doesn&amp;#39;t crash when resolvers return an error; instead, it includes these errors in the GraphQL response with a 200 HTTP status code.&lt;/p&gt;
&lt;p&gt;You can see this in the example shown below, where I made a query to create a league and intentionally failed to include the required &lt;code&gt;name&lt;/code&gt; field:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-08/graceful-error-handling.png&quot; alt=&quot;Graceful Error Handling&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As you can see, returning errors as tuples allows the developer to handle expected failures whichever way they wish, without crashing the request flow.&lt;/p&gt;
&lt;p&gt;For an exception to be raised in Absinthe, the following conditions need to be met:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Having actual bugs in the code. For example, undefined function modules and so forth.&lt;/li&gt;
&lt;li&gt;Database or Ecto errors that are not handled at the context level.&lt;/li&gt;
&lt;li&gt;Absinthe middleware errors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are not necessarily the only conditions, but they represent a big percentage of what would cause Absinthe to raise exceptions.&lt;/p&gt;
&lt;p&gt;With that in mind, let&amp;#39;s use an Absinthe middleware to set up a custom instrumentation and catch a resolver error that would have otherwise gone under the radar.&lt;/p&gt;
&lt;h2&gt;Custom Instrumenting Absinthe Errors&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s assume we want to surface a resolver error when a user tries to fetch a team without a valid ID.&lt;/p&gt;
&lt;p&gt;The relevant &lt;code&gt;get_team/3&lt;/code&gt; resolver function is shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WendigoWeb.Resolvers.TeamResolver do
  alias Wendigo.Context.Teams
  alias WendigoWeb.Error

  def get_team(_parent, %{id: id}, _resolution) do
    case Teams.get(id) do
      nil -&amp;gt;
        {:error, &amp;quot;Team not found: #{id}&amp;quot;}
      team -&amp;gt;
        {:ok, team}
    end
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But like I mentioned earlier, this wouldn&amp;#39;t show up as an error on AppSignal since Absinthe would still return a &lt;code&gt;200&lt;/code&gt; status code. To make sure the error is surfaced as we want, we need to set up an Absinthe middleware.&lt;/p&gt;
&lt;h3&gt;Absinthe Middlewares&lt;/h3&gt;
&lt;p&gt;In Absinthe, a middleware functions as a layer that processes GraphQL requests as they flow through an application, allowing you to perform tasks like error handling, logging, authorization checks, or data transformation before or after resolvers execute.&lt;/p&gt;
&lt;p&gt;For the purpose of error tracking, middlewares are particularly valuable because they can intercept and process any errors that occur during field resolution, whether they&amp;#39;re from failed database queries, validation issues, or other runtime problems.&lt;/p&gt;
&lt;p&gt;With that in mind, let&amp;#39;s set up a middleware called &lt;code&gt;ErrorReporter&lt;/code&gt; to handle resolution errors:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/wendigo_web/middleware/error_reporter.ex

defmodule WendigoWeb.Middleware.ErrorReporter do
  @behaviour Absinthe.Middleware

  def call(resolution, _config) do
    case resolution.errors do
      [] -&amp;gt; resolution
      errors -&amp;gt;
        if span = Appsignal.Tracer.current_span() do
          formatted_errors = Enum.map(errors, &amp;amp;format_error/1)
          error_message = Enum.join(formatted_errors, &amp;quot;, &amp;quot;)

          error = %RuntimeError{
            message: error_message
          }

          Appsignal.Span.add_error(
            span,
            error,
            %{
              graphql_error: true,
              validation_error: true
            }
          )

          Appsignal.Span.set_sample_data(span, &amp;quot;graphql&amp;quot;, %{
            query: resolution.definition.name || &amp;quot;anonymous&amp;quot;,
            path: Absinthe.Resolution.path(resolution)
          })
        end

        resolution
    end
  end

  defp format_error(%{message: message}), do: message
  defp format_error(error), do: inspect(error)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, edit the schema to include this middleware:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/wendigo_web/graphql/schema.ex

defmodule WendigoWeb.GraphQL.Schema do
  ...

  # Middleware
  def middleware(middleware, _field, _object) do
    middleware ++ [WendigoWeb.Middleware.ErrorReporter]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s see how this works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ErrorReporter&lt;/code&gt; middleware is added to all schema operations through the &lt;code&gt;middleware/3&lt;/code&gt; function shown in the code snippet above.&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;get_team/3&lt;/code&gt; is called, the middleware receives a resolution object for each GraphQL field. If there are no errors, the resolution proceeds.&lt;/li&gt;
&lt;li&gt;If there are errors, the middleware formats each error as a string; multiple errors are joined together using commas and sent to AppSignal using the current span.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having mentioned AppSignal&amp;#39;s &amp;quot;span&amp;quot;, here&amp;#39;s what it is and how it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Appsignal.Span&lt;/code&gt; represents a single unit of work in a tracing call. The &lt;code&gt;add_error()&lt;/code&gt; function attaches error information to the span as well as any metadata tags that might be available. In the same token, the &lt;code&gt;set_sample_data()&lt;/code&gt; function is used to add context about a GraphQL request to enrich the data that will appear on AppSignal when the span data is sent.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Appsignal.Tracer&lt;/code&gt; is used for tracking the request flow in the app. The &lt;code&gt;current_span()&lt;/code&gt; function returns the active trace span if it&amp;#39;s available.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, whenever a resolver is executed, the middleware will run with the ability to catch and report errors from field resolvers, input validation, schema validations, runtime errors, and so forth.&lt;/p&gt;
&lt;p&gt;A good example of middleware in action is shown in the screenshots below, which highlight a resolution error that has been reported in the AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-08/resolver-error.png&quot; alt=&quot;Resolver Error&quot;/&gt;&lt;/p&gt;
&lt;p&gt;There&amp;#39;s more detail about the error here:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-08/resolver-error-details.png&quot; alt=&quot;Resolver Error Details&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we&amp;#39;ve explored how to effectively track and monitor errors in an Absinthe GraphQL API using AppSignal. We&amp;#39;ve covered the various types of GraphQL errors you might encounter, from schema validation to resolver errors, and demonstrated how to set up custom error tracking using Absinthe middleware.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Understanding Stack Traces in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/08/05/understanding-stack-traces-in-elixir.html"/>
    <id>https://blog.appsignal.com/2025/08/05/understanding-stack-traces-in-elixir.html</id>
    <published>2025-08-05T00:00:00+00:00</published>
    <updated>2025-08-05T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s explore the fundamentals of stack traces in Elixir, how to read and interpret them, and some best practices for debugging and error handling.</summary>
    <content type="html">&lt;p&gt;If you have spent any time working with Elixir in a production setting — or even just building a side project — you&amp;#39;ve likely encountered a stack trace. Stack traces can appear intimidating at the outset, especially since Elixir&amp;#39;s error messages are often more detailed than those in other languages. However, they are a powerful tool for understanding what went wrong in your code.&lt;/p&gt;
&lt;p&gt;Early in my Elixir journey, I found stack traces to be a bit overwhelming. They seemed to contain a lot of information that I didn&amp;#39;t know how to interpret. While we have the luxury of LLMs like ChatGPT to help us understand these traces today, it&amp;#39;s still essential to know how to read and interpret them independently.&lt;/p&gt;
&lt;p&gt;Effective debugging is crucial when developing applications for commercial or production use. Stack traces are a key tool in your debugging arsenal, helping you quickly identify the source of an error and trace it back to its origin.&lt;/p&gt;
&lt;p&gt;As with many other aspects of the Elixir ecosystem, stack traces are shaped by the underlying principles of simplicity, explicitness, and fault tolerance.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll explore the fundamentals of stack traces in Elixir, how to read and interpret them, and some best practices for debugging and error handling.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s define a stack trace.&lt;/p&gt;
&lt;h2&gt;What Is a Stack Trace?&lt;/h2&gt;
&lt;p&gt;I like to think of stack traces as a story that tells you how your program reached a specific breaking point. They&amp;#39;re a snapshot of all the function calls that led up to an error, starting from the top-level function that was called.&lt;/p&gt;
&lt;p&gt;At a high level, stack traces reflect a program&amp;#39;s call history — a breadcrumb trail that shows how you got to where you are. Each line in a stack trace represents a function call, starting from the most recent and going back to the initial call that triggered the error.&lt;/p&gt;
&lt;p&gt;However, there is a catch: Elixir runs on the BEAM VM, a platform optimized for concurrency and fault tolerance. An Elixir application is actually composed of thousands of lightweight processes that run concurrently, each on its own isolated stack. So, when an error occurs, the stack trace you see is only for the process that crashed, not the entire application.&lt;/p&gt;
&lt;p&gt;This is a crucial concept to keep in mind. &lt;strong&gt;A stack trace tells the local story of a single process, not the global story of an entire application&lt;/strong&gt;. Broader system behaviour emerges from how supervisors, links, and other OTP mechanisms interact with the crashed process.&lt;/p&gt;
&lt;h3&gt;Stack Traces in the BEAM (Erlang VM)&lt;/h3&gt;
&lt;p&gt;The BEAM&amp;#39;s approach to error handling is simple but powerful: errors are expected, processes are allowed to fail, and systems should recover gracefully. Rather than burying exceptions or attempting to rescue every failure, Elixir (and Erlang before it) encourages developers to &amp;quot;let it crash&amp;quot; and rely on supervision trees to restart failed processes.&lt;/p&gt;
&lt;p&gt;When something goes wrong in an Elixir application, one of three primary errors can occur: &lt;code&gt;raise/1&lt;/code&gt;, &lt;code&gt;exit/1&lt;/code&gt;, or &lt;code&gt;throw/1&lt;/code&gt;. Each of these functions generates a stack trace that tells the story of how the error propagated through the system.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;raise/1&lt;/code&gt;: This function is used to raise an exception, which can be caught by a &lt;code&gt;try/rescue&lt;/code&gt; block. When an exception is raised, the stack trace will show the function call that raised the exception, along with the call history that led up to it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exit/1&lt;/code&gt;: This function is used to terminate a process. When a process exits, it can send an exit signal to other processes, which may also generate a stack trace if those processes are linked to the exiting process.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;throw/1&lt;/code&gt;: This function is used for non-local returns, allowing you to exit from a function and return to a different point in the call stack. It can also generate a stack trace, but its usage is less common than &lt;code&gt;raise/1&lt;/code&gt; and &lt;code&gt;exit/1&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The BEAM VM is designed to handle errors gracefully, and stack traces are a key tool for understanding what went wrong and how to recover from it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key takeaway:&lt;/strong&gt; Errors do not bubble up globally; they are local to processes. Supervisors and linked processes may receive notifications, but stack traces themselves belong to the failing process.&lt;/p&gt;
&lt;h3&gt;Differences Between Elixir and Erlang Stack Traces&lt;/h3&gt;
&lt;p&gt;Although Elixir runs on the BEAM VM, just like Erlang, both languages have very different approaches to presentation, semantics, and abstractions around stack traces. This is mostly due to Elixir&amp;#39;s focus on developer experience and its goal of being a more approachable language for newcomers.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Presentation&lt;/strong&gt;: Elixir stack traces are designed to be more human-readable than Erlang&amp;#39;s. They include additional context, such as module and function names, and they format the output in a way that is easier to understand at a glance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Semantics&lt;/strong&gt;: Elixir&amp;#39;s stack traces are more focused on the functional programming paradigm, while Erlang&amp;#39;s stack traces are more aligned with the actor model. This means that Elixir&amp;#39;s stack traces often include more information about function calls and their arguments, while Erlang&amp;#39;s stack traces may focus more on the process and message-passing aspects of the system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Abstractions&lt;/strong&gt;: Elixir provides higher-level abstractions for error handling, such as &lt;code&gt;try/rescue&lt;/code&gt; and &lt;code&gt;try/catch&lt;/code&gt;, which are not present in Erlang. This means that Elixir&amp;#39;s stack traces may include additional information about the context in which the error occurred, such as the specific clause that was matched or the arguments that were passed to the function.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Reading and Interpreting an Elixir Stack Trace&lt;/h2&gt;
&lt;p&gt;So far, we have covered the general concepts around stack traces and, specifically, how they are generated in the BEAM VM. But all that theory is useless if you don&amp;#39;t know how to read a stack trace when you see one.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at a simple example of a stack trace generated by an Elixir application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;** (ArithmeticError) bad argument in arithmetic expression
 :erlang.+(&amp;quot;foo&amp;quot;, 1)
 my_app/lib/my_module.ex:10: MyModule.add/2
 (my_app 0.1.0) my_app.ex:5: MyApp.run/0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When an error occurs, Elixir prints out a stack trace that is comprised of the following elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Error Type&lt;/strong&gt;: The type of error that occurred, in this case &lt;code&gt;ArithmeticError&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Message&lt;/strong&gt;: A description of the error, in this case &lt;code&gt;bad argument in arithmetic expression&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function Calls&lt;/strong&gt;: A list of function calls that led to the error, starting from the most recent call and going back to the initial call that triggered the error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Module and Function&lt;/strong&gt;: The module and function where the error occurred, in this case &lt;code&gt;MyModule.add/2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Line Number&lt;/strong&gt;: The line number in the source code where the error occurred, in this case &lt;code&gt;my_app/lib/my_module.ex:10&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, in this example, the error occurred in the &lt;code&gt;add/2&lt;/code&gt; function of the &lt;code&gt;MyModule&lt;/code&gt; module, specifically on line 10 of the &lt;code&gt;my_module.ex&lt;/code&gt; file. The error was caused by an attempt to add a string (&lt;code&gt;&amp;quot;foo&amp;quot;&lt;/code&gt;) to a number (&lt;code&gt;1&lt;/code&gt;), which is not a valid operation in Elixir.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at another example, this time a GenServer crash:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;** (FunctionClauseError) no function clause matching in MyApp.Worker.handle_call/3
 my_app/lib/my_app/worker.ex:15: MyApp.Worker.handle_call({:unknown, 123}, {#PID&amp;lt;0.142.0&amp;gt;, #Reference&amp;lt;0.0.4.6&amp;gt;}, %{})
 (stdlib 4.0) gen_server.erl:689: :gen_server.try_handle_call/4
 (stdlib 4.0) gen_server.erl:721: :gen_server.handle_msg/6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Take a pause here to look at the stack trace and try to understand what went wrong on your own before reading the explanation below.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this case, the error is a &lt;code&gt;FunctionClauseError&lt;/code&gt;, which means that the function &lt;code&gt;handle_call/3&lt;/code&gt; in the &lt;code&gt;MyApp.Worker&lt;/code&gt; module was called with arguments that did not match any of its defined clauses. The stack trace shows that the error occurred on line 15 of the &lt;code&gt;worker.ex&lt;/code&gt; file, and it provides the specific arguments that were passed to the function: &lt;code&gt;{:unknown, 123}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The stack trace also shows the call history that led to the error, including the &lt;code&gt;try_handle_call/4&lt;/code&gt; and &lt;code&gt;handle_msg/6&lt;/code&gt; functions from the &lt;code&gt;gen_server&lt;/code&gt; module. This information can help you understand how the error propagated through the system and where to look for potential fixes.&lt;/p&gt;
&lt;p&gt;A few tips that can help you read and interpret stack traces more effectively:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start from the top of the stack trace and work your way down. The first line usually contains the most relevant information about the error.&lt;/li&gt;
&lt;li&gt;Stack traces often include both Elixir and Erlang layers. Focus on your own modules first, and then look at the Erlang functions if needed.&lt;/li&gt;
&lt;li&gt;When chasing down an error, start from the topmost Elixir module in your codebase and work your way down.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Debugging Tools and Techniques in Elixir&lt;/h2&gt;
&lt;p&gt;So you have read the stack trace and you know where the error occurred, but how do you go about fixing it?&lt;/p&gt;
&lt;p&gt;The following sections will cover some of the most common debugging tools and techniques available in Elixir.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Logging and Inspection&lt;/h3&gt;
&lt;p&gt;Sometimes you don&amp;#39;t need an interactive debugger to figure out what is going on in your code. A simple &lt;code&gt;IO.inspect/2&lt;/code&gt; or &lt;code&gt;Logger.debug/1&lt;/code&gt; can go a long way in helping you understand the state of your application.&lt;/p&gt;
&lt;p&gt;Elixir gives us a few options, but the most common ones are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;IO.inspect/2&lt;/code&gt; for quick, inline data inspection:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IO.inspect(data, label: &amp;quot;Incoming data&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Logger.debug/1&lt;/code&gt; or &lt;code&gt;Logger.info/1&lt;/code&gt; for production-aware logging:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;require Logger
Logger.error(&amp;quot;Unexpected state in handle_call: #{inspect(state)}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Interactive Debugging&lt;/h3&gt;
&lt;p&gt;Sometimes you need to step through your code line by line to understand what is going on. Elixir provides a couple of tools for interactive debugging: &lt;code&gt;dbg/2&lt;/code&gt; and &lt;code&gt;IEx.pry&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Use &lt;code&gt;iex -S mix&lt;/code&gt; for live exploration. Reproduce bugs interactively.&lt;/p&gt;
&lt;h4&gt;Using &lt;code&gt;dbg/2&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The built-in &lt;code&gt;dbg/2&lt;/code&gt; macro (introduced in Elixir 1.14) allows inline debugging by printing both the value of an expression and the expression itself. This is particularly useful for quickly inspecting values during runtime without modifying too much of your code.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
 def calculate(a, b) do
 dbg(a + b)
 end
end

Example.calculate(2, 3)
# Output:
# dbg(2 + 3) #=&amp;gt; 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;dbg/2&lt;/code&gt; prints the expression &lt;code&gt;2 + 3&lt;/code&gt; and its result &lt;code&gt;5&lt;/code&gt;. This makes it easier to understand what is happening in your code.&lt;/p&gt;
&lt;h4&gt;Using &lt;code&gt;IEx.pry&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;For more advanced debugging, you can use &lt;code&gt;IEx.pry&lt;/code&gt; to pause the execution of your code and interact with it in a live IEx session. This is similar to setting a breakpoint in traditional debuggers.&lt;/p&gt;
&lt;p&gt;To use &lt;code&gt;IEx.pry&lt;/code&gt;, you need to include the &lt;code&gt;require IEx&lt;/code&gt; statement and call &lt;code&gt;IEx.pry/0&lt;/code&gt; where you want to pause execution.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
 def calculate(a, b) do
 require IEx
 IEx.pry()
 a + b
 end
end

Example.calculate(2, 3)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the code reaches &lt;code&gt;IEx.pry/0&lt;/code&gt;, it will pause and open an interactive shell where you can inspect variables, evaluate expressions, and step through the code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To use &lt;code&gt;IEx.pry&lt;/code&gt;, you must run your application with &lt;code&gt;iex -S mix&lt;/code&gt; and ensure the &lt;code&gt;:debugger&lt;/code&gt; application starts. If the debugger is not running, you will see a message like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;** (RuntimeError) cannot pry: the shell is not running or the debugger is not enabled
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Raising, Catching, and Handling Exceptions&lt;/h2&gt;
&lt;p&gt;As mentioned, Elixir, like Erlang, embraces the &amp;quot;let it crash&amp;quot; philosophy.&lt;/p&gt;
&lt;p&gt;Instead of trying to handle every possible error within a process, Elixir encourages developers to allow processes to fail and rely on supervision trees to restart them in a clean state. This approach simplifies error handling and ensures that the system remains robust and fault-tolerant.&lt;/p&gt;
&lt;p&gt;However, there are scenarios where raising and catching errors is necessary. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Input Validation&lt;/strong&gt;: When user input or external data is invalid, raising an exception can provide clear feedback about what went wrong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Boundary Layers&lt;/strong&gt;: At the boundaries of your system (e.g., APIs, file I/O, or database interactions), catching errors allows you to handle failures gracefully and provide meaningful error messages to users or clients.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Critical Cleanup&lt;/strong&gt;: In cases where resources (e.g., files, sockets, or database connections) need to be cleaned up, using &lt;code&gt;try/after&lt;/code&gt; ensures that cleanup happens even if an error occurs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Why Raise and Catch Errors?&lt;/h3&gt;
&lt;p&gt;While the &amp;quot;let it crash&amp;quot; philosophy works well for many scenarios, there are times when you need more control over error handling, including:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Graceful Degradation&lt;/strong&gt;: In user-facing applications, you can catch errors to provide a fallback or a friendly error message instead of crashing the process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Context&lt;/strong&gt;: Raising custom exceptions with meaningful messages can make debugging easier by providing more context about what went wrong.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Controlled Recovery&lt;/strong&gt;: In some cases, you may want to catch an error, log it, and retry the operation or take an alternative action.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def fetch_user_data(user_id) do
 try do
 # Simulate a risky operation
 raise &amp;quot;User not found&amp;quot; if user_id == nil
 {:ok, %{id: user_id, name: &amp;quot;John Doe&amp;quot;}}
 rescue
 e in RuntimeError -&amp;gt; {:error, e.message}
 end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the function raises an exception if the &lt;code&gt;user_id&lt;/code&gt; is &lt;code&gt;nil&lt;/code&gt;. However, it also catches the exception and returns an error tuple, allowing the caller to handle the failure gracefully.&lt;/p&gt;
&lt;p&gt;By combining the &amp;quot;let it crash&amp;quot; philosophy with deliberate error handling where appropriate, you can build resilient and user-friendly systems.&lt;/p&gt;
&lt;h3&gt;Raising Exceptions&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;raise/1&lt;/code&gt; or &lt;code&gt;raise/2&lt;/code&gt; to deliberately trigger errors:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;raise &amp;quot;Something went wrong!&amp;quot;
raise ArgumentError, &amp;quot;invalid argument passed&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Define custom exceptions for clarity:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.MyError do
 defexception message: &amp;quot;default message&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And raise it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;raise MyApp.MyError, message: &amp;quot;Custom error&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Catching Exceptions&lt;/h3&gt;
&lt;p&gt;You can catch errors using &lt;code&gt;try/rescue&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
 risky_call()
rescue
 e in RuntimeError -&amp;gt; IO.puts(&amp;quot;Caught: #{e.message}&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For &lt;code&gt;throw/1&lt;/code&gt;, use &lt;code&gt;try/catch&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
 throw(:error)
catch
 :throw, :error -&amp;gt; &amp;quot;Caught throw&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;code&gt;try/after&lt;/code&gt; to ensure cleanup happens:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
 File.read!(&amp;quot;some_file.txt&amp;quot;)
after
 IO.puts(&amp;quot;Finished file operation&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Best Practice&lt;/strong&gt;: Don&amp;#39;t rescue all exceptions blindly. It breaks the &amp;quot;let it crash&amp;quot; principle and can hide bugs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Rescuing exceptions truncates the stack trace to the rescue point. If you catch too early, you lose important debugging context.&lt;/p&gt;
&lt;h2&gt;Next Steps&lt;/h2&gt;
&lt;p&gt;Create a sandbox project and experiment with different error scenarios. Here are a few ideas that you can try:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a simple GenServer and trigger a &lt;code&gt;FunctionClauseError&lt;/code&gt; by sending an unexpected message.&lt;/li&gt;
&lt;li&gt;Raise an exception in a &lt;code&gt;try&lt;/code&gt; block and see how the stack trace changes when you rescue it.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;dbg/2&lt;/code&gt; to inspect the call stack and see how it changes as you step through your code.&lt;/li&gt;
&lt;li&gt;Protocols and behaviours are a great way to learn about stack traces. Create a protocol and implement it in different modules, then call the protocol function with different arguments to see how the stack trace changes.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Logger&lt;/code&gt; to log different levels of messages and see how they appear in the console.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, treat errors as opportunities to learn and improve your code. Stack traces are a powerful tool for understanding what went wrong and how to fix it. By mastering stack traces and debugging techniques, you&amp;#39;ll be better equipped to build robust and reliable Elixir applications.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we covered a lot of ground on stack traces and debugging in Elixir. Here are the key takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stack traces in Elixir tell the story of a single process, not the entire application.&lt;/li&gt;
&lt;li&gt;Elixir&amp;#39;s &amp;quot;let it crash&amp;quot; philosophy means errors are expected and systems should recover gracefully.&lt;/li&gt;
&lt;li&gt;To read stack traces effectively, start from the top and focus on your application&amp;#39;s modules.&lt;/li&gt;
&lt;li&gt;Debugging tools like &lt;code&gt;IO.inspect/2&lt;/code&gt;, &lt;code&gt;Logger&lt;/code&gt;, and interactive debugging can help you understand errors.&lt;/li&gt;
&lt;li&gt;Exception handling should be purposeful and limited, preserving the valuable context that stack traces provide.&lt;/li&gt;
&lt;li&gt;Well-designed supervision trees and meaningful error messages make production systems more resilient.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As with anything in programming, debugging is a skill that improves with practice. The more you work with Elixir and its stack traces, the more comfortable you&amp;#39;ll become in reading and interpreting them.&lt;/p&gt;
&lt;h2&gt;Further Reading and Resources&lt;/h2&gt;
&lt;p&gt;To deepen your understanding of error handling and debugging in Elixir, I recommend the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/try-catch-and-rescue.html&quot;&gt;The official Elixir documentation on try, catch, and rescue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.erlang.org/doc/system/errors.html&quot;&gt;The Erlang docs for insights into errors&lt;/a&gt; and underlying BEAM behavior&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.manning.com/books/elixir-in-action-third-edition&quot;&gt;&amp;quot;Elixir in Action&amp;quot; by Saša Jurić&lt;/a&gt;, which covers OTP patterns and error handling extensively&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/designing-for-scalability/9781449361556/&quot;&gt;&amp;quot;Designing for Scalability with Erlang/OTP&amp;quot; by Francesco Cesarini and Steve Vinoski&lt;/a&gt; for a deeper understanding of fault tolerance&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elixirforum.com/&quot;&gt;The Elixir Forum&lt;/a&gt; for community discussions on debugging techniques&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.appsignal.com/learning-center/understanding-elixir-error-messages&quot;&gt;Understanding Elixir error messages and stack traces&lt;/a&gt; in AppSignal&amp;#39;s Learning Center&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Oban for Elixir Monitoring Using AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/07/22/an-introduction-to-oban-for-elixir-monitoring-using-appsignal.html"/>
    <id>https://blog.appsignal.com/2025/07/22/an-introduction-to-oban-for-elixir-monitoring-using-appsignal.html</id>
    <published>2025-07-22T00:00:00+00:00</published>
    <updated>2025-07-22T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this article, we&#039;ll learn about Oban&#039;s fundamentals, potential pitfalls, and how to leverage AppSignal&#039;s monitoring capabilities for your Oban setup.</summary>
    <content type="html">&lt;p&gt;Background task processing is something that many developers may encounter when building Elixir applications. This might include sending emails asynchronously, posting and fetching data from an API, and more.&lt;/p&gt;
&lt;p&gt;Oban, a powerful and persistent job processing library, offers a reliable way to handle background tasks, scheduled operations, and more. However, like any complex system, Oban requires careful monitoring to ensure its smooth operation, identify bottlenecks, and prevent unexpected failures.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll learn about the fundamentals of Oban, its potential pitfalls, and how to leverage AppSignal&amp;#39;s monitoring to gain valuable insights into your Oban setup.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Elixir and the Phoenix framework installed on your local computer.&lt;/li&gt;
&lt;li&gt;An AppSignal account. If you don&amp;#39;t have one, &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;sign up for a free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An Elixir/Phoenix app to play around with. If you don&amp;#39;t have one, you &lt;a href=&quot;https://github.com/iamaestimo/phoenix_liveview_email_subscription_app&quot;&gt;can fork this one&lt;/a&gt; that we&amp;#39;ll use throughout this tutorial.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Introducing Oban&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/oban-bg/oban&quot;&gt;Oban&lt;/a&gt; is a robust background job processing library for Elixir that uses PostgreSQL, MySQL, or SQLite 3 for storing job queues. Unlike other job processing solutions, Oban doesn&amp;#39;t require Redis or other external dependencies beyond your existing database.&lt;/p&gt;
&lt;h3&gt;Key Features of Oban&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Persistence&lt;/strong&gt;: Jobs are stored in the database, ensuring they survive application restarts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrency Control&lt;/strong&gt;: Jobs can be organized into queues with configurable concurrency limits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduled Jobs&lt;/strong&gt;: It offers support for one-off and recurring jobs with precision scheduling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Job Prioritization&lt;/strong&gt;: Within each queue, jobs can be assigned different priority levels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Built-in retry mechanisms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unique Jobs&lt;/strong&gt;: Oban provides mechanisms to prevent job duplication with uniqueness constraints.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In terms of structure, Oban consists of workers, which are the modules that define job processing logic, queues, and supervisors, used to manage job execution. This architecture makes it very good for reliable background processing in Elixir apps.&lt;/p&gt;
&lt;h2&gt;Introducing Our Example App and Setting up Oban&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll use a simple email subscription app for this tutorial. A user will be able to submit their email address, and the app will then send a scheduled email using background job queues powered by Oban.&lt;/p&gt;
&lt;p&gt;This app should provide enough context for you to learn about Oban and how to monitor it using AppSignal.&lt;/p&gt;
&lt;h3&gt;Adding Oban to an Elixir Project&lt;/h3&gt;
&lt;p&gt;Oban&amp;#39;s installation is very straightforward. Begin by adding the following packages to your app&amp;#39;s &lt;code&gt;mix.exs&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
...

{:oban, &amp;quot;~&amp;gt; 2.19&amp;quot;},
{:igniter, &amp;quot;~&amp;gt; 0.5&amp;quot;, only: [:dev]},
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, fetch the newly added dependencies with &lt;code&gt;mix deps.get&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Installing Oban Using Igniter&lt;/h3&gt;
&lt;p&gt;Previously, after adding Oban and running the &lt;code&gt;mix oban.install&lt;/code&gt; command, we had to modify the generated migration file manually.&lt;/p&gt;
&lt;p&gt;But now, with the addition of the &lt;a href=&quot;https://hexdocs.pm/igniter/readme.html&quot;&gt;Igniter&lt;/a&gt; library, after running &lt;code&gt;mix oban.install&lt;/code&gt;, the manual modification of the generated migration file is not needed.&lt;/p&gt;
&lt;p&gt;Now that you know what Igniter is for, go ahead and install Oban with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix oban.install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run the generated migrations with &lt;code&gt;mix ecto.migrate&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Adding AppSignal to the Project&lt;/h2&gt;
&lt;p&gt;Open up the &lt;code&gt;mix.exs&lt;/code&gt; file, then edit it as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
...
defp deps do
    [
        ...
        {:appsignal, &amp;quot;~&amp;gt; 2.8&amp;quot;},
        {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
    ]
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: The AppSignal instrumentation for Phoenix apps is available through a separate &lt;code&gt;appsignal_phoenix&lt;/code&gt; package, which depends on the core Elixir &lt;code&gt;appsignal&lt;/code&gt; package.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Then run &lt;code&gt;mix deps.get&lt;/code&gt; to fetch the package, followed by the command &lt;code&gt;mix appsignal.install &amp;lt;YOUR APPSIGNAL API KEY&amp;gt;&lt;/code&gt; to install AppSignal.&lt;/p&gt;
&lt;p&gt;You can choose how you want AppSignal configured for the project from the following options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customizing the name of your application.&lt;/li&gt;
&lt;li&gt;Choosing the configuration method to be used (two options are available: via an environment variable or through the use of a configuration file).&lt;/li&gt;
&lt;/ul&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Once you&amp;#39;ve made your choices, you should get an output similar to the one shown below if the process runs without issues.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Validating Push API key: Valid! 🎉
What is your application&amp;#39;s name? [email_subscription_app]: email_subscription_app
There are two methods of configuring AppSignal in your application.
  Option 1: Using a &amp;quot;config/appsignal.exs&amp;quot; file. (1)
  Option 2: Using system environment variables.  (2)
What is your preferred configuration method? [1]: 1
Writing config file config/appsignal.exs: Success!
Linking config to config/config.exs: Success!
Activating dev environment: Success!
Activating prod environment: Success!
...
AppSignal installed! 🎉
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you should have AppSignal installed, and your app will start sending data to your dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/initial-appsignal-dashboard-screen.png&quot; alt=&quot;AppSignal dashboard for example app&quot;/&gt;&lt;/p&gt;
&lt;p&gt;So far, we have a Phoenix application integrated with Oban and AppSignal. We can now turn our attention to the question of how to monitor Oban.&lt;/p&gt;
&lt;p&gt;But before we do that, let&amp;#39;s learn about some of Oban&amp;#39;s challenges and potential points of failure for insights into where to focus our monitoring efforts.&lt;/p&gt;
&lt;h2&gt;Common Oban Challenges and Potential Points of Failure&lt;/h2&gt;
&lt;p&gt;Like any background job framework, Oban can encounter various challenges that affect performance and reliability. Understanding these potential issues is crucial for effective monitoring and maintenance. Let&amp;#39;s explore some of these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Queue overloading&lt;/strong&gt; - When jobs are enqueued faster than they can be processed, queues can build up rapidly. This backlog can lead to increased memory usage, slower overall system performance, and delayed job execution. It is particularly problematic for time-sensitive operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Failed jobs and error handling&lt;/strong&gt; - Jobs can fail for various reasons, including database timeouts, API rate limits, and so forth. Without proper error handling and monitoring, failed jobs might slip through the cracks, or worse, create a sequence of other failures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database contention&lt;/strong&gt; - Since Oban uses your database for job storage, high job throughput can lead to database contention. This manifests as lock timeouts and increased query times and can impact your application&amp;#39;s core functionality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Worker crashes&lt;/strong&gt; - When workers crash unexpectedly, jobs might be abandoned or stuck in a &amp;quot;running&amp;quot; state, and without proper supervision, these orphaned jobs can clog your system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While these examples represent common challenges with Oban, they&amp;#39;re just a few of the potential issues you might encounter.&lt;/p&gt;
&lt;p&gt;With this knowledge of Oban&amp;#39;s architecture and potential pitfalls, we&amp;#39;re now ready to explore how AppSignal can help us gain visibility into our job processing system and detect problems before they impact users.&lt;/p&gt;
&lt;h2&gt;Monitoring Oban Using AppSignal&lt;/h2&gt;
&lt;p&gt;Once you&amp;#39;ve added the AppSignal package, it will automatically instrument Oban job workers and queue metrics out of the box.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/automatic-instrumentation-oban.png&quot; alt=&quot;Automatic instrumentation of Oban&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tip: AppSignal also adds an Oban namespace, which you can use to filter for Oban-specific metrics.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A few Oban metrics are automatically made available. Let&amp;#39;s start by looking at job execution time.&lt;/p&gt;
&lt;h3&gt;Job Execution Time Metrics&lt;/h3&gt;
&lt;p&gt;This metric captures the duration spent by a worker to perform a particular job. For example, in the email subscription app, when a user submits an email, the &lt;code&gt;WelcomeEmailWorker&lt;/code&gt; is used to send a welcome email.&lt;/p&gt;
&lt;p&gt;The code below shows the Oban worker responsible for processing the welcome email:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/email_subscription_app/workers/welcome_email_worker.ex

defmodule EmailSubscriptionApp.Workers.WelcomeEmailWorker do
  use Oban.Worker, queue: :default
  alias EmailSubscriptionApp.Emails.{EmailSender, Mailer}

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{&amp;quot;email&amp;quot; =&amp;gt; email}}) do
    email
    |&amp;gt; EmailSender.welcome_email()
    |&amp;gt; Mailer.deliver()
    |&amp;gt; case do
      {:ok, _} -&amp;gt; :ok
      {:error, reason} -&amp;gt;
        raise &amp;quot;Mailer delivery error: #{inspect(reason)}&amp;quot;
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is automatically captured on the AppSignal dashboard, as you can see below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/welcome-email-worker-instrumentation.png&quot; alt=&quot;Automatic instrumentation of the welcome email worker&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/welcome-email-worker-instrumentation-2.png&quot; alt=&quot;Welcome email duration metrics&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Metrics for Slow Jobs&lt;/h3&gt;
&lt;p&gt;AppSignal will also automatically capture slow jobs. The dashboard below shows you what this looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/slow-oban-workers.png&quot; alt=&quot;Slow Oban jobs&quot;/&gt;&lt;/p&gt;
&lt;p&gt;AppSignal also automatically instruments Oban errors. Let&amp;#39;s see how that looks next.&lt;/p&gt;
&lt;h3&gt;Automatic Metrics for Oban Errors&lt;/h3&gt;
&lt;p&gt;AppSignal provides excellent error instrumentation for Oban, as you can see from the screenshots below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/error-automatic-instrumentation-1.png&quot; alt=&quot;Error instrumentation - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;More details are made available when you click into a particular error:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/error-automatic-instrumentation-2.png&quot; alt=&quot;Error instrumentation - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/error-automatic-instrumentation-3.png&quot; alt=&quot;Error instrumentation - 3&quot;/&gt;&lt;/p&gt;
&lt;p&gt;While it&amp;#39;s great having automatic instrumentation for some of the more common metrics, there will be times when you need to go beyond these.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say you wanted to know the total number of welcome emails sent within a certain period of time or the number of failed ecommerce orders; such metrics might not be automatically captured. For custom metrics like these, it&amp;#39;s necessary to implement custom instrumentation for Oban.&lt;/p&gt;
&lt;h2&gt;Custom Metrics for Deeper Insights&lt;/h2&gt;
&lt;p&gt;Using the email subscription app as an example, let&amp;#39;s say we are interested in counting the number of successful email subscriptions that are initiated on the app. This is a rather simple metric, but it will give you an idea of what&amp;#39;s possible with AppSignal.&lt;/p&gt;
&lt;p&gt;To accomplish our task, we can add custom instrumentation to the &lt;code&gt;WelcomeEmailWorker&lt;/code&gt; since this Oban worker is responsible for sending the initial user email.&lt;/p&gt;
&lt;p&gt;Edit the worker&amp;#39;s code as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/email_subscription_app/workers/welcome_email_worker.ex

defmodule EmailSubscriptionApp.Workers.WelcomeEmailWorker do
  use Oban.Worker, queue: :default
  alias EmailSubscriptionApp.Emails.{EmailSender, Mailer}

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{&amp;quot;email&amp;quot; =&amp;gt; email}}) do
    Appsignal.instrument(&amp;quot;welcome_email_worker&amp;quot;, fn -&amp;gt;
      email
      |&amp;gt; EmailSender.welcome_email()
      |&amp;gt; Mailer.deliver()
      |&amp;gt; case do
        {:ok, _} -&amp;gt;
          Appsignal.increment_counter(&amp;quot;successful_email.subscriptions&amp;quot;, 1)
        {:error, reason} -&amp;gt;
          raise &amp;quot;Mailer delivery error: #{inspect(reason)}&amp;quot;
      end
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s what&amp;#39;s going on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We use &lt;code&gt;Appsignal.instrument/2&lt;/code&gt; to wrap the worker&amp;#39;s &lt;code&gt;perform&lt;/code&gt; function and create a span (which will be sent over to AppSignal as an event).&lt;/li&gt;
&lt;li&gt;Then, we use &lt;code&gt;Appsignal.increment_counter/3&lt;/code&gt; to count the number of successful email deliveries, which we use as the sign of a successful subscription.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once that is done, we need to set up a custom dashboard to visualize this metric.&lt;/p&gt;
&lt;h2&gt;Setting up Custom Dashboards for Oban on AppSignal&lt;/h2&gt;
&lt;p&gt;Start by clicking on the &amp;quot;Add dashboard&amp;quot; button on the left-hand side menu:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/adding-custom-dashboard-1.png&quot; alt=&quot;Adding a custom dashboard - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Then the &amp;quot;Create a dashboard&amp;quot; button on the next screen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/adding-custom-dashboard-2.png&quot; alt=&quot;Adding a custom dashboard - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now give the new dashboard a title and description:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/adding-custom-dashboard-3.png&quot; alt=&quot;Adding a custom dashboard - 3&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Adding a Custom Oban Graph&lt;/h3&gt;
&lt;p&gt;Next, click on the &amp;quot;Add graph&amp;quot; button of your new dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/adding-custom-dashboard-4.png&quot; alt=&quot;Adding a custom dashboard - 4&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Then you&amp;#39;ll see the fields needed for the custom graph:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/adding-custom-dashboard-5.png&quot; alt=&quot;Adding a custom graph&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Here is a brief outline of what you&amp;#39;re looking at in terms of the fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a. &lt;strong&gt;Graph title&lt;/strong&gt; - Input a relevant title for the graph.&lt;/li&gt;
&lt;li&gt;b. &lt;strong&gt;Graph description&lt;/strong&gt; - Add a description.&lt;/li&gt;
&lt;li&gt;c and d. &lt;strong&gt;Graph metrics&lt;/strong&gt; - This one needs a bit more of an explanation. &lt;em&gt;Metric&lt;/em&gt; here is the metric we added to our app&amp;#39;s counter function. In the email subscription app, this is &lt;code&gt;successful_email.subscriptions&lt;/code&gt; (as you can see from the metrics in the screenshot below):&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/adding-graph-metric-1.png&quot; alt=&quot;Adding custom metrics - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: I won&amp;#39;t go into the details of all the custom graph and dashboard features available, but you can explore them further in the &lt;a href=&quot;https://docs.appsignal.com/metrics/dashboards.html&quot;&gt;dashboards documentation&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Finally, when you add a custom graph, you&amp;#39;ll start seeing the custom metrics:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-07/adding-graph-metric-2.png&quot; alt=&quot;Custom graph&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we&amp;#39;ve explored how to integrate and monitor Oban with AppSignal in an Elixir/Phoenix application. We started by setting up Oban for background job processing and then added AppSignal for monitoring.&lt;/p&gt;
&lt;p&gt;We discussed common challenges with Oban and how AppSignal&amp;#39;s automatic instrumentation can help you gain insights into job execution times, slow jobs, and errors. Additionally, we demonstrated how to create custom metrics and dashboards for more granular monitoring tailored to your application&amp;#39;s needs.&lt;/p&gt;
&lt;p&gt;By leveraging these tools, you can ensure your background job processing is efficient, reliable, and well-monitored, ultimately leading to a more robust and performant application.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Advanced Strategies to Deploy Phoenix Applications with Kamal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/07/08/advanced-strategies-to-deploy-phoenix-applications-with-kamal.html"/>
    <id>https://blog.appsignal.com/2025/07/08/advanced-strategies-to-deploy-phoenix-applications-with-kamal.html</id>
    <published>2025-07-08T00:00:00+00:00</published>
    <updated>2025-07-08T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In part two of this series, we dive into more advanced methods to deploy Phoenix applications using Kamal.</summary>
    <content type="html">&lt;p&gt;In the first part of our series, we explored how Kamal simplifies Docker-based deployments while providing a cloud-like developer experience.
We covered the basics of containerizing Phoenix applications, configuring Kamal, managing secrets, and implementing a CI/CD pipeline for automated deployments.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve established a solid foundation for deploying Phoenix applications, it&amp;#39;s time to dive deeper into more advanced deployment scenarios that leverage both Kamal&amp;#39;s flexibility and the Elixir ecosystem&amp;#39;s robust distributed capabilities.
These strategies will help you scale your Phoenix applications beyond a single instance and build resilient, production-grade systems.&lt;/p&gt;
&lt;p&gt;The Erlang VM (BEAM) was designed from the ground up for building fault-tolerant, distributed systems.
When combined with Kamal&amp;#39;s multi-role deployment capabilities, we can create sophisticated architectures that maximize the strengths of both technologies.
Whether you&amp;#39;re running background processing with dedicated worker containers, setting up clustered Elixir nodes, or implementing zero-downtime scaling strategies, Kamal provides the infrastructure orchestration layer while Phoenix and the BEAM provide the application resilience.&lt;/p&gt;
&lt;p&gt;In this second part, we&amp;#39;ll explore how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure multi-role deployments to separate web servers from background workers&lt;/li&gt;
&lt;li&gt;Establish Elixir clustering across containers for distributed Phoenix applications&lt;/li&gt;
&lt;li&gt;Implement advanced monitoring solutions for production visibility&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By the end of this article, you&amp;#39;ll know how to deploy complex Phoenix applications that can scale horizontally while maintaining the operational simplicity that Kamal offers.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s begin by extending our basic deployment to handle multiple roles and establish communication between them.&lt;/p&gt;
&lt;h2&gt;Multi-Role Deployments with Kamal&lt;/h2&gt;
&lt;p&gt;One of the most common requirements for growing Phoenix applications is the need to separate concerns between web servers and background workers.
This separation allows you to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Scale web servers and background jobs independently based on their specific resource needs&lt;/li&gt;
&lt;li&gt;Isolate potentially resource-intensive background tasks from affecting web request performance&lt;/li&gt;
&lt;li&gt;Implement different deployment strategies for each component of your application&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Kamal makes this separation straightforward through its multi-role deployment configuration.
Let&amp;#39;s expand our deployment setup to include dedicated worker containers.&lt;/p&gt;
&lt;h3&gt;Configuring Worker Roles in Kamal&lt;/h3&gt;
&lt;p&gt;A web role is responsible for handling user-facing requests — this is your Phoenix Server.
A worker role can, for example, be responsible for running background jobs such as sending emails or processing data.
There is no limit to what roles you can define with Kamal.
However, &lt;code&gt;web&lt;/code&gt; is a special role that receives requests from kamal proxy if it is enabled.&lt;/p&gt;
&lt;p&gt;Let us update our &lt;code&gt;deploy.yml&lt;/code&gt; file to define both web and worker roles:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;service: my-app
image: my-user/my-app

servers:
  web:
    hosts:
      - 123.456.789.10 # Your web server IP

  worker:
    hosts:
      # Can be same or different server
      - 123.456.789.10
    # Containers can pass custom environment variables - these will be merged
    # with the common env vars
    env:
      clear:
        ROLE: WORKER
    # Containers can run a different command
    # cmd: /app/bin/my_app worker

# Common configuration for all roles
env:
  secret:
    - SECRET_KEY_BASE
    - DATABASE_URL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration introduces several important concepts.
We define both &lt;code&gt;web&lt;/code&gt; and &lt;code&gt;worker&lt;/code&gt; roles, each with its own servers and commands.
Each role starts a separate container with the possibility of overriding the command or environment for that container.
Using the &lt;code&gt;env&lt;/code&gt; configuration inside the role, we can provide different environment variables for different roles.&lt;/p&gt;
&lt;p&gt;Note that Kamal expects there to be a &lt;code&gt;web&lt;/code&gt; role (which is the default if you skip the role label and just define the IPs inside the server configuration).
You can set a different &lt;code&gt;primary_role&lt;/code&gt; in the root configuration.&lt;/p&gt;
&lt;h3&gt;Modifying Your Phoenix Application for Worker Processes&lt;/h3&gt;
&lt;p&gt;To take advantage of this multi-role setup, your Phoenix application needs a way to start different processes based on the container&amp;#39;s role.
This depends largely on what background worker strategy you are using.
Let&amp;#39;s see an example using the popular background jobs engine &lt;a href=&quot;https://github.com/oban-bg/oban&quot;&gt;Oban&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this code, we first read the &lt;code&gt;ROLE&lt;/code&gt; environment variable to determine the container&amp;#39;s role.
If the &lt;code&gt;ROLE&lt;/code&gt; is &amp;quot;WEB&amp;quot;, we start the Phoenix Endpoint to handle HTTP requests and an Oban server without any queues.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;ROLE&lt;/code&gt; is &amp;quot;WORKER&amp;quot;, we don&amp;#39;t start the Phoenix Endpoint.
Instead, we start an Oban server with the default configuration to process background jobs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app/application.ex
defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    role = System.get_env(&amp;quot;ROLE&amp;quot;, &amp;quot;WEB&amp;quot;)

    children =
      get_children_for_role(role)
      |&amp;gt; Enum.filter(&amp;amp; &amp;amp;1)

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end

  defp common_children() do
    # Common components for all roles
    [
      MyApp.Repo,
      MyApp.JobRepo,
      {Phoenix.PubSub, name: MyApp.PubSub},
      {Cluster.Supervisor,
       [
         Application.get_env(:libcluster, :topologies, []),
         [name: MyApp.ClusterSupervisor]
       ]}
    ]
  end

  defp get_children_for_role(&amp;quot;WEB&amp;quot;) do
    oban_config_without_queues =
      Application.fetch_env!(:my_app, Oban)
      |&amp;gt; Keyword.merge(queues: [], plugins: [])

    common_children() ++
      [
        MyAppWeb.Endpoint,
        {Oban, oban_config_without_queues}
      ]
  end

  defp get_children_for_role(&amp;quot;WORKER&amp;quot;) do
    common_children() ++
      [
        {Oban, Application.fetch_env!(:my_app, Oban)}
      ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this structure, your application will start different components based on the container&amp;#39;s role:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web containers will start the Phoenix Endpoint to handle HTTP requests.
They will start an Oban server with no queues, so you can call &lt;code&gt;Oban.insert&lt;/code&gt; to enqueue background jobs, but those jobs won&amp;#39;t be processed.&lt;/li&gt;
&lt;li&gt;Worker containers will not start Phoenix Endpoint but instead start &lt;code&gt;Oban&lt;/code&gt; with default configuration (you&amp;#39;ll have this in &lt;code&gt;config/config.exs&lt;/code&gt; or similar) to handle background jobs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach allows you to share code between roles while maintaining separation of concerns at runtime.&lt;/p&gt;
&lt;h3&gt;Deploying Multi-Role Applications&lt;/h3&gt;
&lt;p&gt;With this configuration in place, deploying becomes just as simple as before:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle exec kamal deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Kamal will automatically deploy both web and worker containers according to the configuration.
You can also target specific roles for deployment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle exec kamal deploy --roles=web  # Deploy only web servers
bundle exec kamal deploy --roles=worker  # Deploy only workers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This granular control is especially useful for making role-specific changes without disrupting your entire application.&lt;/p&gt;
&lt;h2&gt;Elixir Clustering Across Containers&lt;/h2&gt;
&lt;p&gt;One of Elixir&amp;#39;s greatest strengths is its ability to run as a distributed system across multiple nodes.
A node is an instance of the Erlang VM running your application.
For example, in the above configuration, we started one web server and one worker — each of these is a separate node.
While they can work fine in isolation, clustering allows them to coordinate better.&lt;/p&gt;
&lt;p&gt;For example, clustering makes global process registration possible, so any node can locate and communicate with a specific process running elsewhere in the cluster.
In case of failure, supervision trees can restart processes on different nodes, improving fault tolerance.
Clustering also enables distributed task queues, shared ETS/Mnesia tables, and the ability to broadcast events across all nodes — essential for real-time features in modern applications.&lt;/p&gt;
&lt;p&gt;When deploying with Kamal, we can take advantage of this capability to create resilient clusters that span multiple containers and even multiple physical servers.&lt;/p&gt;
&lt;h3&gt;Setting Up &lt;code&gt;libcluster&lt;/code&gt; for Container Discovery&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/bitwalker/libcluster&quot;&gt;libcluster&lt;/a&gt; library provides strategies for automatic node discovery and connection.
For deployments spanning a single node, we&amp;#39;ll use the &lt;code&gt;Cluster.Strategy.Gossip&lt;/code&gt; strategy, which works well in containerized environments.&lt;/p&gt;
&lt;p&gt;First, add &lt;code&gt;libcluster&lt;/code&gt; to your dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
defp deps do
  [
    # ...existing deps...
    {:libcluster, &amp;quot;~&amp;gt; 3.5&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, configure &lt;code&gt;libcluster&lt;/code&gt; in your application supervision tree:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app/application.ex
defmodule MyApp.Application do
  use Application

defp common_children() do
    [
      {Cluster.Supervisor, [libcluster_topologies(), [name: MyApp.ClusterSupervisor]]},
      # ...existing children...
    ]
  end

  defp libcluster_topologies() do
    # When using releases, this can come from config/runtime.exs using Application.get_env/2
    [
      gossip: [
        strategy: Cluster.Strategy.Gossip,
        config: [
          multicast_addr: System.get_env(&amp;quot;CLUSTER_MULTICAST_ADDRESS&amp;quot;, &amp;quot;233.252.1.32&amp;quot;),
          port: System.get_env(&amp;quot;CLUSTER_PORT&amp;quot;, &amp;quot;45892&amp;quot;) |&amp;gt; String.to_integer()
        ]
      ]
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Creating a Distribution Configuration for Release&lt;/h3&gt;
&lt;p&gt;If you&amp;#39;re using Elixir releases (which is recommended for production), you&amp;#39;ll need to properly configure distribution settings in your release configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# rel/env.sh.eex
#!/bin/sh

# Set the release distribution to work on the same node and not require FQDN
export RELEASE_DISTRIBUTION=sname
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Updating Kamal Configuration for Node Communication&lt;/h3&gt;
&lt;p&gt;For containers to communicate properly in a cluster, we need to ensure two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The nodes have the same value for the &lt;code&gt;RELEASE_COOKIE&lt;/code&gt; environment variable.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can use any of the methods discussed in Part 1 of this post to expose this variable.
Just make sure that you add it to your environment secrets inside &lt;code&gt;config/deploy.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# config/deploy.yml
# ...existing configuration...
env:
  secrets:
    - RELEASE_COOKIE
    # ...other secrets...
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;The nodes can reach each other.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For this, we don&amp;#39;t need to configure anything as long as the containers are on the same node.
This is because Kamal automatically creates a Docker network that all nodes join and can communicate with each other.&lt;/p&gt;
&lt;p&gt;Once the nodes join the same cluster, you&amp;#39;ll unlock a host of benefits that come with it.
For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you use &lt;code&gt;Phoenix.PubSub&lt;/code&gt; with the &lt;code&gt;PG2&lt;/code&gt; adapter (which is the default), you&amp;#39;ll see that PubSub messages are now delivered automatically across nodes.
That means you can broadcast from a background job and subscribe to that event inside a LiveView.&lt;/li&gt;
&lt;li&gt;Communicate with processes on other nodes simply like you would do if they were on the same node.
OTP handles everything else at the BEAM level once the nodes are clustered — no need for Redis, Kafka, or other synchronization tools or message brokers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Clustering Containers Across Different Nodes&lt;/h3&gt;
&lt;p&gt;As you&amp;#39;ve probably already guessed, the &lt;code&gt;Gossip&lt;/code&gt; strategy only works across containers on a single node.
But that doesn&amp;#39;t mean that you&amp;#39;ll have to constrain clustered deployments to a single node.
We can use other &lt;code&gt;libcluster&lt;/code&gt; topologies to enable clustering across nodes, but it&amp;#39;ll just need a little more work.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start by configuring &lt;code&gt;libcluster&lt;/code&gt; to use the &lt;a href=&quot;https://github.com/supabase/libcluster_postgres&quot;&gt;&lt;code&gt;libcluster_postgres&lt;/code&gt;&lt;/a&gt; strategy.
This strategy uses a shared PostgreSQL database to store a list of nodes in the cluster.
All nodes listen for and send notifications to a shared Postgres channel.
When a node comes online, it begins to broadcast its name in a &amp;quot;heartbeat&amp;quot; message to the channel.
All other nodes that receive this message attempt to connect to it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/runtime.exs

# Libcluster is using Postgres for Node discovery
# The library only accepts keyword configs, so the DATABASE_URL has to be
# parsed and put together with the ssl pieces from above.
postgres_config = Ecto.Repo.Supervisor.parse_url(System.fetch_env!(&amp;quot;DATABASE_URL&amp;quot;))

libcluster_db_config =
  [port: 5432]
  |&amp;gt; Keyword.merge(postgres_config)
  |&amp;gt; Keyword.take([:hostname, :username, :password, :database, :port])
  |&amp;gt; Keyword.merge(ssl: System.get_env(&amp;quot;DATABASE_SSL&amp;quot;, &amp;quot;true&amp;quot;) == &amp;quot;true&amp;quot;)
  |&amp;gt; Keyword.merge(ssl_opts: [cacerts: :public_key.cacerts_get()])
  |&amp;gt; Keyword.merge(parameters: [])
  |&amp;gt; Keyword.merge(channel_name: &amp;quot;my_app_clustering&amp;quot;)

config :libcluster,
  topologies: [
    postgres: [
      strategy: LibclusterPostgres.Strategy,
      config: libcluster_db_config
    ]
  ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next part is ensuring that the containers can communicate with each other across nodes.
Unfortunately, Kamal doesn&amp;#39;t (yet) allow exposing custom ports from the servers over the public network.&lt;/p&gt;
&lt;p&gt;To enable nodes to connect to each other, Erlang uses a small service called The Erlang Port Mapper Daemon (epmd).
It runs on each machine and acts as a name server, mapping node names to their corresponding IP addresses and ports.&lt;/p&gt;
&lt;p&gt;So to allow clustering across physical nodes, we&amp;#39;ll need to start a separate accessory and proxy the &lt;a href=&quot;https://www.erlang.org/docs/26/man/epmd&quot;&gt;epmd&lt;/a&gt; requests to the application servers through that proxy.&lt;/p&gt;
&lt;p&gt;First, configure a &lt;code&gt;Traefik&lt;/code&gt; proxy as a Kamal accessory inside the configuration.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# config/deploy.yml
accessories:
  traefik:
    service: traefik
    image: traefik:v3.1
    options:
      publish:
        - &amp;quot;6789:6789&amp;quot;
    cmd: &amp;quot;--providers.docker --providers.docker.exposedByDefault=false --entryPoints.epmd.address=:6789 --log.level=INFO&amp;quot;
    volumes:
      - &amp;quot;/var/run/docker.sock:/var/run/docker.sock&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To start it, simply run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle exec kamal accessory boot traefik
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will start the accessory on all servers defined in your configuration.&lt;/p&gt;
&lt;p&gt;We can use Traefik&amp;#39;s labeling system to label our containers so that it forwards all TCP traffic received on the epmd port 6789 on the host to port 6789 of the container.&lt;/p&gt;
&lt;p&gt;This way, we start a Traefik proxy on each server to forward epmd requests to the application containers.
Each node uses the &lt;code&gt;libcluster_postgres&lt;/code&gt; strategy to discover nodes in the cluster.
Once &lt;code&gt;libcluster&lt;/code&gt; is able to discover nodes and epmd is accessible across all nodes, Erlang is able to establish a cluster.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;servers:
  web:
    hosts:
      - 1.2.3.4
    env:
      clear:
        RELEASE_NODE: my_app_web@1.2.3.4
    labels:
      traefik.enable: true
      traefik.tcp.routers.epmd.rule: &amp;quot;ClientIP(`0.0.0.0/0`)&amp;quot;
      traefik.tcp.routers.epmd.priority: 5
      traefik.tcp.routers.epmd.entryPoints: epmd
      traefik.tcp.routers.epmd.service: epmd
      traefik.tcp.services.epmd.loadBalancer.server.port: 6789
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The deployment steps don&amp;#39;t change.
All you need is still only a single command to deploy your apps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle exec kamal deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Advanced Monitoring Solutions&lt;/h2&gt;
&lt;p&gt;In a production environment, visibility into your application&amp;#39;s performance and health is crucial.
While Kamal makes deployments easy, it&amp;#39;s very important to keep monitoring your app for any problems that might occur.&lt;/p&gt;
&lt;p&gt;AppSignal provides comprehensive monitoring for &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;Elixir and Phoenix applications&lt;/a&gt;.
Setting it up with your Kamal deployment is straightforward.&lt;/p&gt;
&lt;p&gt;First, add AppSignal to your dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
defp deps do
  [
    # ...existing deps...
    {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install it inside the app with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix appsignal.install YOUR_PUSH_API_KEY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Update your Kamal configuration to inject the AppSignal push API key as a secret:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# config/deploy.yml
# ...existing configuration...

env:
  clear:
    APPSIGNAL_APP_ENV: &amp;quot;production&amp;quot;
  secret:
    - DATABASE_URL
    - APPSIGNAL_PUSH_API_KEY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.appsignal.com/elixir/integrations/phoenix.html&quot;&gt;Check out our full guide to integrate AppSignal into Phoenix&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Logging and Log Management&lt;/h3&gt;
&lt;p&gt;In addition to application monitoring, AppSignal also makes it easy to store application logs for debugging issues.&lt;/p&gt;
&lt;p&gt;Once the AppSignal SDK is integrated, we can configure the Erlang &lt;code&gt;:logger&lt;/code&gt; to use the &lt;code&gt;Appsignal.Logger.Handler&lt;/code&gt; module as a handler, by calling the &lt;code&gt;Appsignal.Logger.Handler.add/2&lt;/code&gt; function in your &lt;code&gt;Application.start/2&lt;/code&gt; callback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app/application.ex
defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    Appsignal.Logger.Handler.add(&amp;quot;phoenix&amp;quot;)
    # start supervisor and other config...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Scaling Strategies&lt;/h2&gt;
&lt;p&gt;As your application grows, you&amp;#39;ll need to scale horizontally to handle increased traffic.
Kamal only supports manual scaling out of the box.
To scale, manually adjust your deployment configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# config/deploy.yml
servers:
  web:
    hosts:
      - 123.456.789.10
      - 123.456.789.11
      - 123.456.789.12

  worker:
    hosts:
      - 123.456.789.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This configuration deploys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3 web containers (1 per server)&lt;/li&gt;
&lt;li&gt;1 worker container&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To scale up, you simply update the configuration and redeploy (with &lt;code&gt;bundle exec kamal deploy&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;While this might look like a downside compared to most cloud service offerings that provide some form of auto-scaling during peak loads, it is important to note that Kamal does not maintain a running daemon.
It manages deployments on a push-based model (where updates are pushed to the server on deployments), so auto-scaling is impossible.
To deal with this, Kamal advocates over-provisioning for the spikes since the baseline cost (moving from cloud providers to self-hosted servers or budget providers like Hetzner) is several times lower.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this comprehensive guide to advanced Phoenix deployment with Kamal, we&amp;#39;ve explored how to leverage both technologies to build resilient production systems.
By implementing multi-role deployments, Elixir clustering, and advanced monitoring, you now have the tools to deploy even the most complex Phoenix applications with confidence.&lt;/p&gt;
&lt;p&gt;The combination of Phoenix&amp;#39;s distributed capabilities and Kamal&amp;#39;s simple yet powerful deployment model gives you the best of both worlds: the resilience and scalability of the Erlang VM with the operational simplicity of modern containerized deployments.&lt;/p&gt;
&lt;p&gt;As you continue to evolve your deployment strategy, remember that simplicity and automation are key.
Each enhancement to your deployment process should make your life easier, not more complex.
With Kamal and Phoenix, you have the foundation to build systems that scale seamlessly while remaining manageable for small teams.&lt;/p&gt;
&lt;p&gt;Happy deploying!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Advanced Ecto for Elixir Monitoring with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/07/01/advanced-ecto-for-elixir-monitoring-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2025/07/01/advanced-ecto-for-elixir-monitoring-with-appsignal.html</id>
    <published>2025-07-01T00:00:00+00:00</published>
    <updated>2025-07-01T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of our two-part series, we&#039;ll set up more advanced Ecto monitoring using AppSignal.</summary>
    <content type="html">&lt;p&gt;In our previous article, we explored the basics of monitoring Ecto with AppSignal, covering everything from initial setup to tracking key metrics such as query execution time and resource consumption. We even set up custom instrumentation for database connection pools to gain deeper insights into our application&amp;#39;s performance. However, setting up monitoring is just the first step toward maintaining a healthy, high-performing Elixir application. The real power comes from knowing what to do with all that data.&lt;/p&gt;
&lt;p&gt;In this second part of our Ecto monitoring series, we&amp;#39;ll take your monitoring strategy to the next level. We&amp;#39;ll explore how to establish meaningful baseline metrics, set up intelligent alerts that notify you of issues before they affect users, and implement robust exception monitoring to catch database problems early.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Elixir, the Phoenix framework, and PostgreSQL installed on your development environment.&lt;/li&gt;
&lt;li&gt;Some experience with Elixir and the Phoenix framework.&lt;/li&gt;
&lt;li&gt;An AppSignal account. If you don&amp;#39;t have one ready, &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;sign up for a free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An Elixir/Phoenix app to follow along with. If you don&amp;#39;t have one, &lt;a href=&quot;https://github.com/iamaestimo/ecto_2_blog_app&quot;&gt;fork the blog app we&amp;#39;ll be using for this tutorial&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s get started.&lt;/p&gt;
&lt;h2&gt;Establishing Baseline Metrics for Ecto&lt;/h2&gt;
&lt;p&gt;Database monitoring is only valuable as long as you know how to distinguish between &amp;quot;healthy&amp;quot; and &amp;quot;unhealthy&amp;quot; database metrics. Obviously, whether a metric is healthy or not is relative to the application, the hosting environment, and a host of other variables.&lt;/p&gt;
&lt;p&gt;All the same, it&amp;#39;s important to establish baseline metrics to see whether your database is performing optimally or not.&lt;/p&gt;
&lt;h3&gt;Why Should You Use Baseline Metrics?&lt;/h3&gt;
&lt;p&gt;Baseline metrics allow you to define what normal database behavior looks like versus abnormal behavior which could impact your users negatively.&lt;/p&gt;
&lt;p&gt;Baseline metrics define expected performance characteristics under normal conditions. They help us answer questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How many database operations per second should we expect?&lt;/li&gt;
&lt;li&gt;How are connection pools being utilized when our app is under load?&lt;/li&gt;
&lt;li&gt;How long does a query take?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By answering such questions, you will be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use data-driven optimization&lt;/strong&gt; - By knowing the healthy ranges under which your app&amp;#39;s Ecto database operates, you can set up optimizations backed up by data. For example, if fetching posts from your blog app takes 30 ms, you could reliably set up database indexes that reduce this to, say, 20 ms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Early problem detection&lt;/strong&gt; - By knowing what &amp;quot;normal&amp;quot; metrics look like, you can set up an early warning system to alert you to problems affecting Ecto in advance. For example, imagine a query that normally takes 10 ms to execute, which suddenly spikes to 200 ms in execution time. With a baseline already set up, such a spike is flagged as an anomaly that needs to be checked.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smart resource planning&lt;/strong&gt; - Knowing how to allocate server resources for your app is very key. Instead of flying blind when it comes to allocating server resources, you can use baseline trends to figure out if your app&amp;#39;s resources should be scaled up or down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have an idea of what baseline metrics are and why we need them, let&amp;#39;s learn how to set some up in the next section.&lt;/p&gt;
&lt;h3&gt;Collecting Initial Performance Data&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Note: We won&amp;#39;t go through the process of setting up a new application and adding the AppSignal integration; the previous article has a good walk-through, in case you need a refresher.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before actually collecting any performance data for our baseline needs, we need to decide what data is important.&lt;/p&gt;
&lt;p&gt;In the context of the blog app, the following operations make good examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fetching a post with comments from the database by hitting the &lt;code&gt;GET /posts/:id&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;Creating a post using the &lt;code&gt;POST /posts&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;Something that will put a strain on the database index, like listing all posts (&lt;code&gt;GET /posts&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These examples allow us to collect our initial baseline metrics for Ecto.&lt;/p&gt;
&lt;p&gt;Having established the baseline metrics we&amp;#39;ll be collecting, the next step is to simulate web traffic that will allow AppSignal to collect the data we need and display it in a dashboard.&lt;/p&gt;
&lt;h3&gt;Using a Load Testing Tool to Collect Baseline Metrics&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll use a load testing tool to simulate web traffic to some of the endpoints mentioned above.&lt;/p&gt;
&lt;p&gt;There are many load testing tools you can choose from, but for the purposes of this tutorial, we&amp;#39;ll go with the &lt;a href=&quot;https://github.com/grafana/k6&quot;&gt;k6 load testing tool&lt;/a&gt;, an easy-to-use command-line tool for load testing. You can &lt;a href=&quot;https://grafana.com/docs/k6/latest/set-up/install-k6/&quot;&gt;follow this guide to install k6&lt;/a&gt; on your machine.&lt;/p&gt;
&lt;p&gt;Once you have k6 ready to go, let&amp;#39;s create a simple script that simulates website traffic for one hundred virtual users and fetches a blog post with comments on it.&lt;/p&gt;
&lt;h3&gt;Baseline Metrics for Fetching a Post With Comments&lt;/h3&gt;
&lt;p&gt;The blog app&amp;#39;s &lt;em&gt;Post&lt;/em&gt; context contains the &lt;code&gt;get_post!()&lt;/code&gt; function. This fetches a post by &lt;em&gt;id&lt;/em&gt; and also preloads any comments on that post:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/blog_app/posts.ex

defmodule BlogApp.Posts do
  ...

  def get_post!(id), do: Repo.get!(Post, id) |&amp;gt; Repo.preload(:comments)

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s create a simple k6 script that will simulate a hundred virtual users fetching a post:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: Create this script in a different folder from your app&amp;#39;s folder.&lt;/em&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// k6_simulations/script.js

import http from &amp;quot;k6/http&amp;quot;;
import { sleep } from &amp;quot;k6&amp;quot;;

export const options = {
  vus: 100, // 100 virtual users
  duration: &amp;quot;30s&amp;quot;, // How long the test will run
};

export default function () {
  http.get(&amp;quot;http://localhost:4000/posts/6&amp;quot;); // We fetch a post with a few comments...
  sleep(1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;In the script, we define:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vus&lt;/code&gt; - the number of virtual users to simulate&lt;/li&gt;
&lt;li&gt;&lt;code&gt;duration&lt;/code&gt; - how long the simulation will take (in seconds)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sleep(1)&lt;/code&gt; - to simulate real user behavior where users pause between requests, as opposed to continuous requests, which wouldn&amp;#39;t be normal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then run the script with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;k6 run script.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the script runs and you give &lt;a href=&quot;https://www.appsignal.com/elixir/ecto-monitoring&quot;&gt;AppSignal some time to gather the data from Ecto&lt;/a&gt;, you should get a dashboard as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/simulating-fetching-a-post-k6.png&quot; alt=&quot;AppSignal dashboard for 100vus fetching a post&quot;/&gt;&lt;/p&gt;
&lt;p&gt;From the graph, we can see that it takes about 30 ms to load the post and another 32 ms to load the associated comments.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s see how Ecto behaves when we fetch all posts at once using the same one hundred virtual users.&lt;/p&gt;
&lt;h3&gt;Baseline Metric When the Database Index Is Under Strain&lt;/h3&gt;
&lt;p&gt;For this one, modify the k6 script as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// k6_simulations/script.js

import http from &amp;quot;k6/http&amp;quot;;
import { sleep } from &amp;quot;k6&amp;quot;;

export const options = {
  vus: 100, // 100 virtual users
  duration: &amp;quot;30s&amp;quot;, // How long the test will run
};

export default function () {
  http.get(&amp;quot;http://localhost:4000/posts&amp;quot;); // We fetch all posts
  sleep(1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run it with &lt;code&gt;k6 run script.js&lt;/code&gt;, wait, and then view the resulting dashboard on AppSignal:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/fetching-all-post-k6.png&quot; alt=&quot;Fetching all posts using k6&quot;/&gt;&lt;/p&gt;
&lt;p&gt;From the results, we can see Ecto takes around 117 ms to fetch all posts and comments.&lt;/p&gt;
&lt;p&gt;Now that we have these metrics, the next question is: &amp;quot;What do we consider to be healthy query ranges for Ecto to compare against?&amp;quot;&lt;/p&gt;
&lt;h3&gt;Determining Healthy Ecto Ranges and Benchmarks&lt;/h3&gt;
&lt;p&gt;Determining healthy metrics for Ecto queries is very subjective because no two apps are completely identical in every way, and there are numerous variables that can affect query times.&lt;/p&gt;
&lt;p&gt;That said, the following benchmark metrics are worth considering:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sub-50 ms&lt;/strong&gt; - For common queries, such as fetching single posts and comments, this is a good benchmark to compare against. Our comparison metric of 30 ms - 32 ms falls within this range, which is good and possibly due to us preloading the comments in the &lt;code&gt;get_post()&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;50 ms - 100 ms&lt;/strong&gt; - This is considered normal for heavier queries, for example, fetching all posts and associated comments. From the results we got when we load-tested the blog app, we can see that 72 ms is cutting it really close and may indicate there&amp;#39;s a need to optimize the query.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Greater than 100 ms&lt;/strong&gt; - Queries that fall within this range can be considered &amp;quot;very slow.&amp;quot; Any query in this range needs immediate optimization because the effect of such a slow query will definitely affect user experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we&amp;#39;ve determined the benchmark metrics we can measure our app&amp;#39;s queries against, it would be very convenient if we could get notifications and alerts whenever our app experiences slow queries. AppSignal has an excellent notification and alerting layer that can help us with this.&lt;/p&gt;
&lt;p&gt;In the next section, let&amp;#39;s learn how to set up alerts and notifications.&lt;/p&gt;
&lt;h2&gt;Setting up Effective Alerts for Ecto On AppSignal&lt;/h2&gt;
&lt;p&gt;Having learned about baseline metrics and what to benchmark against, it wouldn&amp;#39;t make sense to keep on manually checking dashboards or discovering performance issues after users complain. Instead, we can make use of &lt;a href=&quot;https://www.appsignal.com/tour/anomaly-detection&quot;&gt;AppSignal&amp;#39;s anomaly detection&lt;/a&gt; to notify us when Ecto queries move from normal to abnormal behavior.&lt;/p&gt;
&lt;p&gt;In this section, we&amp;#39;ll configure alerts that will help you catch database performance problems before they impact your users. We&amp;#39;ll set up alerts for slow queries, but the same techniques can be applied for other metrics such as high database connection usage and other critical metrics that could indicate potential issues with your Ecto setup.&lt;/p&gt;
&lt;p&gt;For our first example, we&amp;#39;ll set up an alert that will trigger whenever an Ecto query takes more than 100 ms to execute.&lt;/p&gt;
&lt;p&gt;We will take the following steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Setting up a trigger&lt;/strong&gt; - A &amp;quot;trigger&amp;quot; is what determines if an alert should be raised.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuring the trigger&lt;/strong&gt; - Set up the trigger to fire whenever a metric exceeds pre-determined bounds.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setting up alert warmup and cooldown&lt;/strong&gt; - As important as alerts can be, you also don&amp;#39;t want them to fire off too many times. Warmups and cooldowns let you control this.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuring the alerting service&lt;/strong&gt; - Here, you get to choose how an alert will be delivered to you. AppSignal gives you a wide choice, from email to SMS alerts, and everything in between.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Setting Up a Trigger&lt;/h3&gt;
&lt;p&gt;To access triggers on the AppSignal dashboard, go to the left-hand side menu, then locate a menu category called &amp;quot;Anomaly detection,&amp;quot; under which you&amp;#39;ll find the &amp;quot;Triggers&amp;quot; menu:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/setting-up-alerts-1.png&quot; alt=&quot;Setting up alerts - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Then, click on the &amp;quot;Add a trigger&amp;quot; button, which opens up a dialog like the one shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/setting-up-alerts-2.png&quot; alt=&quot;Setting up alerts - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;On the new trigger dialog, we have a few options to set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;1. Metric type&lt;/strong&gt; - You can set up a trigger for a variety of metrics: error rates, slow actions, CPU usage, and many more. For our example, we&amp;#39;ll go with &amp;quot;slow actions&amp;quot; since we want to get an alert whenever Ecto queries take too long to execute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2. Namespace&lt;/strong&gt; - Choose the namespace you want to set up the trigger in. &lt;a href=&quot;https://docs.appsignal.com/application/namespaces.html&quot;&gt;Read more on namespaces in AppSignal&amp;#39;s documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3. When to trigger the alert&lt;/strong&gt; - Here&amp;#39;s where you determine the actual conditions under which the trigger will be raised. You can set up a trigger to go off based on the mean, the 90th, or 95th percentile of a metric&amp;#39;s measure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;4. Alert warmup and cooldown&lt;/strong&gt; - These help prevent notification spam. Warmup is the period AppSignal waits before sending the first alert after a trigger condition is met, ensuring the issue persists. Cooldown is the minimum time between subsequent alerts for the same trigger, preventing repeated notifications for ongoing issues.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;5. Notification channel&lt;/strong&gt; - The notification channel to be used. AppSignal gives you a wide choice, including email, SMS, PagerDuty, and others. See more about these in &lt;a href=&quot;https://docs.appsignal.com/application/notification-settings.html&quot;&gt;AppSignal&amp;#39;s notification settings documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After you&amp;#39;ve set up the trigger, it will appear in the active triggers list, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/active-triggers-list.png&quot; alt=&quot;Active triggers list&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now, whenever conditions match the trigger you&amp;#39;ve set, the trigger fires, and the event that sets off the trigger is listed in the anomalies list, as shown in the screenshot below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/anomalies-list.png&quot; alt=&quot;Anomalies list&quot;/&gt;&lt;/p&gt;
&lt;p&gt;At the same time, you&amp;#39;re sent a notification on the notification channel you&amp;#39;ve set up.&lt;/p&gt;
&lt;p&gt;Moving on, let&amp;#39;s now turn our attention to monitoring Ecto errors beyond what is captured by AppSignal&amp;#39;s default settings.&lt;/p&gt;
&lt;h2&gt;Monitoring Custom Errors Using AppSignal&lt;/h2&gt;
&lt;p&gt;By default, AppSignal automatically instruments most of the common Ecto errors, such as non-existent database records. Now, imagine a scenario where you want to track the spam comment submissions within our blog app. How would you handle this? This scenario requires us to set up custom error tracking.&lt;/p&gt;
&lt;p&gt;To begin with, we modify the Comment schema to check for spam comments:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BlogApp.Comments.Comment do
  use Ecto.Schema
  import Ecto.Changeset
  alias BlogApp.Posts.Post

  @spam_phrases [&amp;quot;this is a spam comment&amp;quot;, &amp;quot;buy now&amp;quot;, &amp;quot;make money fast&amp;quot;]

  schema &amp;quot;comments&amp;quot; do
    field :content, :string
    belongs_to :post, Post

    timestamps(type: :utc_datetime)
  end

  @doc false
  def changeset(comment, attrs) do
    comment
    |&amp;gt; cast(attrs, [:content])
    |&amp;gt; validate_required([:content])
    |&amp;gt; validate_no_spam()
  end

  defp validate_no_spam(changeset) do
    content = get_field(changeset, :content) || &amp;quot;&amp;quot;

    if Enum.any?(@spam_phrases, &amp;amp;String.contains?(String.downcase(content), &amp;amp;1)) do
      changeset
      |&amp;gt; add_error(:content, &amp;quot;Spam detected!&amp;quot;)
    else
      changeset
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code uses the &lt;code&gt;validate_no_spam()&lt;/code&gt; function to check for spam comments. If a comment matching any of the pre-determined spam comments — &amp;quot;this is a spam comment&amp;quot;, &amp;quot;buy now&amp;quot;, or &amp;quot;make money fast&amp;quot; — is submitted by a user, a validation error is raised.&lt;/p&gt;
&lt;p&gt;Next, we modify the post controller to track spam comments as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BlogAppWeb.PostController do
  ...

  @spam_error &amp;quot;Spam detected!&amp;quot;

  ...

  def add_comment(conn, %{&amp;quot;post_id&amp;quot; =&amp;gt; post_id, &amp;quot;comment&amp;quot; =&amp;gt; comment_params}) do
    post = Posts.get_post!(post_id)

    case Posts.create_comment(post, comment_params) do
      {:ok, _comment} -&amp;gt;
        conn
        |&amp;gt; put_flash(:info, &amp;quot;Comment added successfully.&amp;quot;)
        |&amp;gt; redirect(to: ~p&amp;quot;/posts/#{post}&amp;quot;)

      {:error, %Ecto.Changeset{} = changeset} -&amp;gt;
        # Track spam attempts
        if changeset.errors[:content] == {@spam_error, []} do
          track_spam_attempt(conn, post_id, comment_params)
        end

        render(conn, :show, post: post, changeset: changeset)
    end
  end

  defp track_spam_attempt(conn, post_id, comment_params) do
    # Get the user&amp;#39;s IP
    ip =
      conn.remote_ip
      |&amp;gt; Tuple.to_list()
      |&amp;gt; Enum.join(&amp;quot;.&amp;quot;)

    # Prepare metadata
    metadata = %{
      content: comment_params[&amp;quot;content&amp;quot;],
      post_id: post_id,
      user_ip: ip,
      path: conn.request_path,
      user_agent: get_req_header(conn, &amp;quot;user-agent&amp;quot;) |&amp;gt; List.first(),
      timestamp: DateTime.utc_now()
    }

    # Send custom error to AppSignal
    Appsignal.send_error(
      :spam_attempt,
      &amp;quot;Spam comment detected&amp;quot;,
      &amp;quot;Content: #{comment_params[&amp;quot;content&amp;quot;]}&amp;quot;,
      [
        namespace: &amp;quot;spam_detection&amp;quot;,
        metadata: metadata,
        tags: [&amp;quot;spam&amp;quot;, &amp;quot;user_content&amp;quot;]
      ]
    )

    # Also increment a counter metric
    Appsignal.increment_counter(&amp;quot;spam_attempts&amp;quot;, 1, metadata)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now with this bit of code, we have the following flow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User submits a spammy comment (for example, &amp;quot;make money fast&amp;quot;).&lt;/li&gt;
&lt;li&gt;The schema validation fails via the &lt;code&gt;validate_no_spam()&lt;/code&gt; function, and a &lt;code&gt;{:content, {&amp;quot;Spam detected!&amp;quot;, []}}&lt;/code&gt; error is added.&lt;/li&gt;
&lt;li&gt;The controller pattern matches the error and executes &lt;code&gt;track_spam_attempt()&lt;/code&gt;, which then triggers a custom event that is sent to AppSignal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And now, when a user submits a spam comment, this is tracked as an error and displayed on the AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/custom-error-capture-1.png&quot; alt=&quot;Custom error capture - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The actual submitted comment is also included:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/custom-error-capture-2.png&quot; alt=&quot;Custom error capture - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;To go further, you can even set up a custom dashboard to track the number of spam comment submissions — but we won&amp;#39;t go into that for now.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we&amp;#39;ve learned how to establish meaningful baseline metrics to help you distinguish between healthy and problematic database behavior in Ecto. We then configured intelligent alerts using AppSignal that notify you before performance issues impact your users and implemented custom error tracking for spam detection.&lt;/p&gt;
&lt;p&gt;With these monitoring strategies in place, you&amp;#39;re now equipped to maintain a high-performing Ecto for Elixir application.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Deploying Phoenix Applications with Kamal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/06/10/deploying-phoenix-applications-with-kamal.html"/>
    <id>https://blog.appsignal.com/2025/06/10/deploying-phoenix-applications-with-kamal.html</id>
    <published>2025-06-10T00:00:00+00:00</published>
    <updated>2025-06-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this post, we dive into how to deploy Phoenix applications using Kamal.</summary>
    <content type="html">&lt;p&gt;Deploying Phoenix applications in production environments poses unique challenges due to Elixir and the Erlang Virtual Machine (VM).&lt;/p&gt;
&lt;p&gt;The ecosystem offers multiple strategies — ranging from releases to mix-based approaches (as detailed in the Phoenix Deployment Guide) — and various platforms employ different methods.
While some rely on buildpacks (for example, Heroku and Gigalixir), others use containerization (like Fly).
These hosted solutions simplify deployment but often come with a premium cost.&lt;/p&gt;
&lt;p&gt;Kamal stands out by providing a cloud-like developer experience while remaining deployable on any infrastructure, from bare metal to cloud VMs.
With a focus on simplicity and convention over configuration, it streamlines Docker-based deployments.
Although it originated in the Rails ecosystem, its language-agnostic approach makes it an excellent fit for Phoenix applications.&lt;/p&gt;
&lt;h2&gt;Understanding Kamal&lt;/h2&gt;
&lt;p&gt;Launched in 2023 by Basecamp (formerly 37signals) and led by David Heinemeier Hansson (DHH), Kamal was created as a straightforward yet powerful deployment tool.
Its core principles — strong defaults modeled on “convention over configuration,” an intuitive CLI with clear feedback, and features such as health checks, rollbacks, and zero-downtime deployments — simplify the Docker workflow, from image building to container orchestration.
This minimizes operational overhead, letting you concentrate on application development.&lt;/p&gt;
&lt;p&gt;When compared to other tools in the Elixir ecosystem, Kamal avoids the infrastructure lock-in and premium costs of Heroku-style solutions while offering a gentler learning curve than Kubernetes.
For Phoenix applications, it strikes a balance between managing distributed systems and maintaining an accessible interface that doesn&amp;#39;t demand a dedicated DevOps team.&lt;/p&gt;
&lt;h2&gt;Preparing Your Phoenix Application&lt;/h2&gt;
&lt;p&gt;Before deploying with Kamal, ensure your Phoenix application is containerized.
You may choose to use releases or run &lt;code&gt;mix phx.server&lt;/code&gt; directly within the container — both approaches require a Dockerfile to copy your source or release bundle.
For releases, run the &lt;code&gt;mix phx.gen.release --docker&lt;/code&gt; task (see the &lt;a href=&quot;https://hexdocs.pm/phoenix/releases.html#containers&quot;&gt;Phoenix Release Deployment Guide&lt;/a&gt;); otherwise, adjust the Dockerfile from the guide as needed.
For secrets management, Kamal’s integration with password managers prevents hardcoding sensitive information.&lt;/p&gt;
&lt;p&gt;With these preparations complete, your Phoenix application will be ready for deployment with Kamal, properly containerized and configured for production environments.&lt;/p&gt;
&lt;h2&gt;Deployment Process&lt;/h2&gt;
&lt;h3&gt;Installing Kamal&lt;/h3&gt;
&lt;p&gt;After containerizing your application, set up Kamal for deployment.
Since Kamal is distributed as a Ruby gem, install Ruby (using version managers like &lt;a href=&quot;https://mise.jdx.dev/&quot;&gt;mise-en-place&lt;/a&gt; or &lt;a href=&quot;https://asdf-vm.com/&quot;&gt;asdf&lt;/a&gt;) and create a Gemfile in your project&amp;#39;s root:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle init
bundle add kamal
bundle install
bundle exec kamal version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then initialize Kamal with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle exec kamal init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This generates key configuration files: &lt;code&gt;config/deploy.yml&lt;/code&gt; for deployment settings, &lt;code&gt;.kamal/secrets&lt;/code&gt; for secret management, and &lt;code&gt;.kamal/hooks&lt;/code&gt; for any custom tasks.&lt;/p&gt;
&lt;h3&gt;Provisioning a Server&lt;/h3&gt;
&lt;p&gt;To deploy an app with Kamal, you&amp;#39;ll need to provision a server.
This could be a cloud server (for example, from Hetzner or a Digital Ocean droplet), a bare-metal server, or even a computer on your local network.
The only requirement is that it be configured with vanilla Ubuntu and your development machine can SSH to it.&lt;/p&gt;
&lt;p&gt;To enable SSH access to the server, copy your SSH public key to &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; on the server.
If you need to generate a key, you can do that with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh-keygen -t ed25519
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Kamal Configuration&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;config/deploy.yml&lt;/code&gt; file defines the deployment setup: the servers&amp;#39; IPs, container settings, and environment variables.
For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Name of your application. Used to uniquely configure containers.
service: my-app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next part is the container image name.
This will be used to upload the image to a container registry, so you&amp;#39;ll need something that the registry understands.
For example, if you are uploading to the GitHub Container Registry, the image name will be &lt;code&gt;&amp;lt;&amp;lt;org-name&amp;gt;&amp;gt;/&amp;lt;&amp;lt;app-name&amp;gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Name of the container image.
image: my-user/my-app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we define the servers the app should be deployed to.
If you are only deploying the web server, the &lt;code&gt;servers&lt;/code&gt; key will contain a single entry (the &lt;code&gt;web&lt;/code&gt; &lt;strong&gt;role&lt;/strong&gt;).
For complex apps (e.g., ones that run background workers), it is possible to start multiple containers per app — either on the same server or different servers.
Additionally, it is also possible to deploy the same &lt;strong&gt;role&lt;/strong&gt; to multiple servers (for example, when you want multiple web servers behind a load balancer).
We&amp;#39;ll see the advanced options available in the next post.&lt;/p&gt;
&lt;p&gt;For now, let&amp;#39;s focus on a single &lt;code&gt;web&lt;/code&gt; server setup.
We&amp;#39;ll need to add the IP of the server we provisioned in the configuration file of the previous step.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Deploy to these servers.
servers:
  web:
    - 192.168.0.1
  # job:
  #   hosts:
  #     - 192.168.0.1
  #   cmd: bin/jobs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we configure the proxy.
Kamal comes with a built-in proxy: the public-facing part of your server, which then forwards all incoming requests to the respective server.
The proxy is capable of handling SSL termination and automatic SSL certificate provisioning via &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let&amp;#39;s Encrypt&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Enable SSL auto certification via Let&amp;#39;s Encrypt.
proxy:
  ssl: true
  host: app.example.com
  # Proxy connects to your container on port 80 by default.
  # app_port: 3000
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Next, we configure the container registry that Kamal uses.
The container registry is where all built images will be uploaded to and then pulled on the servers.
The default is Docker Hub, but many others are supported using the &lt;code&gt;server&lt;/code&gt; configuration.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Credentials for your image host.
registry:
  # Specify the registry server, if you&amp;#39;re not using Docker Hub
  # server: registry.digitalocean.com / ghcr.io / ...
  username: my-user
  password:
    - KAMAL_REGISTRY_PASSWORD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we configure the builder that builds the image from the Dockerfile.
We can mostly leave our app as-is: the defaults are quite sufficient.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Configure builder setup.
builder:
  arch: amd64
  # args: ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s inject environment variables into the containers.
Kamal handles them in two stages: &lt;code&gt;clear&lt;/code&gt; and &lt;code&gt;secret&lt;/code&gt;.
Clear variables have a value defined inline in the configuration file.
The secrets, on the other hand, only have a name inside the configuration file. Kamal uses &lt;code&gt;.kamal/secrets&lt;/code&gt; to read the variable&amp;#39;s name and injects it into the containers.
We&amp;#39;ll learn more about them in the secrets management section of this post.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;# Inject ENV variables into containers (secrets come from .kamal/secrets).
#
# env:
#   clear:
#     DB_HOST: 192.168.0.2
#   secret:
#     - RAILS_MASTER_KEY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are also several other advanced configuration options that we&amp;#39;ll explore later on in this and the next post.&lt;/p&gt;
&lt;h3&gt;Managing Secrets&lt;/h3&gt;
&lt;p&gt;Kamal uses the &lt;code&gt;.kamal/secrets&lt;/code&gt; file to expose sensitive data to containers.
A typical structure is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;SECRETS=$(kamal secrets fetch ...)

REGISTRY_PASSWORD=$(kamal secrets extract REGISTRY_PASSWORD $SECRETS)
DB_PASSWORD=$(kamal secrets extract DB_PASSWORD $SECRETS)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;kamal secrets fetch&lt;/code&gt; &lt;a href=&quot;https://kamal-deploy.org/docs/commands/secrets/&quot;&gt;supports several adapters&lt;/a&gt; including 1Password, LastPass, Bitwarden, among others.&lt;/p&gt;
&lt;p&gt;If you don&amp;#39;t want to use a secrets manager, it is also possible to expose environment variables as secrets by accessing the environment variable using &lt;code&gt;$NAME&lt;/code&gt; inside &lt;code&gt;secrets&lt;/code&gt;.
For example, the below example exposes a secret named &lt;code&gt;REGISTRY_PASSWORD&lt;/code&gt; with the value &lt;code&gt;$KAMAL_REGISTRY_PASSWORD&lt;/code&gt; (the value of the environment variable named &lt;code&gt;KAMAL_REGISTRY_PASSWORD&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Server Bootstrap&lt;/h3&gt;
&lt;p&gt;If this is the first time you are deploying to a server with Kamal, you&amp;#39;ll need to install some tools on the server.
Kamal makes this easy through the &lt;a href=&quot;https://kamal-deploy.org/docs/commands/server/&quot;&gt;&lt;code&gt;kamal server bootstrap&lt;/code&gt;&lt;/a&gt; command.
Once &lt;code&gt;config/deploy.yml&lt;/code&gt; is ready, just run the bootstrap command: it will install Docker and set up your server to host deployments from Kamal.&lt;/p&gt;
&lt;h3&gt;Deploying Your Phoenix Application&lt;/h3&gt;
&lt;p&gt;Now that we know the anatomy of the Kamal configuration and secrets files and our server is ready to handle deployments, let&amp;#39;s get back to deploying our application.&lt;/p&gt;
&lt;p&gt;A basic Phoenix application mostly needs two secrets: &lt;code&gt;SECRET_KEY_BASE&lt;/code&gt; and &lt;code&gt;DATABASE_URL&lt;/code&gt;.
Depending on your use case, you might need more, but Kamal makes it easy to define and expose as many environment variables as you like.
We&amp;#39;ll additionally need a password to access the container registry.&lt;/p&gt;
&lt;p&gt;The simplest way to expose them to your app is through environment-level secrets.
Generate and export the secrets as environment variables.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ mix phx.gen.secret
REALLY_LONG_SECRET
$ export SECRET_KEY_BASE=REALLY_LONG_SECRET
$ export DATABASE_URL=ecto://USER:PASS@HOST/database
$ export KAMAL_REGISTRY_PASSWORD=SOME_REGISTRY_PASSWORD_OR_ACCESS_TOKEN
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then update &lt;code&gt;.kamal/secrets&lt;/code&gt; accordingly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;SECRET_KEY_BASE=$SECRET_KEY_BASE
DATABASE_URL=$DATABASE_URL
REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s a &lt;a href=&quot;https://gist.github.com/sapandiwakar/c99e555ed45f293c7b6b3edcd1dfec40&quot;&gt;minimal &lt;code&gt;deploy.yml&lt;/code&gt;&lt;/a&gt; that makes use of these variables to deploy the application.&lt;/p&gt;
&lt;h3&gt;All Systems Go!&lt;/h3&gt;
&lt;p&gt;Finally, we are there! We can deploy the app with a &lt;a href=&quot;https://kamal-deploy.org/docs/commands/deploy/&quot;&gt;single command&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kamal deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This builds the app, pushes it to the registry, and deploys it on our servers.
The deployment takes place in a secondary container which goes live only after all health checks pass.
If any step of the process fails, the previous app container keeps actively serving all traffic without any interruptions.&lt;/p&gt;
&lt;h3&gt;Accessing Remote Console&lt;/h3&gt;
&lt;p&gt;One of the great features of Kamal for Phoenix applications is the ability to access your IEX console in production.
You can do this with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;bundle exec kamal app exec --interactive --reuse &amp;quot;/app/bin/my_app remote&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be hard to remember, which is where Kamal aliases come in.
Inside the &lt;code&gt;deploy.yml&lt;/code&gt; file, an &lt;code&gt;aliases&lt;/code&gt; entry can be used to define custom commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;aliases:
  console: app exec --interactive --reuse &amp;quot;/app/bin/my_app remote&amp;quot;
  shell: app exec --interactive --reuse &amp;quot;/bin/sh&amp;quot;
  logs: app logs -f
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this in the config, we get three new commands that can be run from the app folder (on the local/developer machine):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;kamal console # Access iex console on the server
kamal shell # Access the shell prompt on the server
kamal logs # Starts tailing application logs from the server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s turn to some more advanced configurations we can do in Phoenix.&lt;/p&gt;
&lt;h2&gt;Advanced Phoenix-Specific Configurations&lt;/h2&gt;
&lt;p&gt;We can make our configuration more advanced by automating database migrations and through GitHub Actions / CI/CD pipelines. Let&amp;#39;s look at automating migrations first.&lt;/p&gt;
&lt;h3&gt;Automating Database Migrations with Kamal&lt;/h3&gt;
&lt;p&gt;Database migrations are one of the most common requirements when deploying applications.
With Phoenix, you typically need to run &lt;code&gt;mix ecto.migrate&lt;/code&gt; before your application starts serving traffic.
While Kamal doesn&amp;#39;t have built-in support specifically for Phoenix migrations, we can leverage Docker&amp;#39;s entrypoint mechanism to automate this process.&lt;/p&gt;
&lt;p&gt;We can create a custom Docker entrypoint script that runs migrations before starting your application.&lt;/p&gt;
&lt;p&gt;First, create a file called &lt;code&gt;docker-entrypoint&lt;/code&gt; in your project&amp;#39;s &lt;code&gt;config&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/sh -e

# If running the server, run migrations first
if [ &amp;quot;$#&amp;quot; -eq 1 ] &amp;amp;&amp;amp; [ &amp;quot;$1&amp;quot; = &amp;quot;/app/bin/server&amp;quot; ]; then
  echo &amp;quot;Running migrations before starting server...&amp;quot;
  /app/bin/migrate
  echo &amp;quot;Migrations completed!&amp;quot;
fi

# Execute the original command
exec &amp;quot;${@}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses the &lt;a href=&quot;https://hexdocs.pm/phoenix/releases.html#ecto-migrations-and-custom-commands&quot;&gt;&lt;code&gt;migrate&lt;/code&gt; script generated when you bundle the app with &lt;code&gt;mix release&lt;/code&gt;&lt;/a&gt;.
If you are using regular &lt;code&gt;mix&lt;/code&gt; commands to run the app, replace them with &lt;code&gt;mix ecto.migrate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then update your Dockerfile to use this entrypoint script.
In the final stage of your Dockerfile, add:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;# Set the entrypoint and default command
ENTRYPOINT [&amp;quot;/app/bin/docker-entrypoint&amp;quot;]
CMD [&amp;quot;/app/bin/server&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this setup, whenever Kamal deploys your application, the Docker container will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Execute the entrypoint script.&lt;/li&gt;
&lt;li&gt;The script detects the server starting.&lt;/li&gt;
&lt;li&gt;The script runs migrations first.&lt;/li&gt;
&lt;li&gt;Then it starts your Phoenix application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This approach ensures that your database is always up to date before your application starts handling requests.
It&amp;#39;s particularly valuable in Kamal&amp;#39;s zero-downtime deployment process, as the new version of your application will only receive traffic after migrations have successfully completed.&lt;/p&gt;
&lt;h3&gt;Integration with GitHub Actions or CI/CD Pipelines&lt;/h3&gt;
&lt;p&gt;The final step in creating a truly modern deployment workflow is to integrate Kamal with your CI/CD pipeline.
This integration brings you closest to the convenience of Platform as a Service (PaaS) offerings like Heroku or Fly, allowing your team to focus on writing code while deployments happen automatically in the background.&lt;/p&gt;
&lt;p&gt;With CI/CD integration, you can automatically deploy when changes are merged to your main branch (optionally after your tests and linting processes pass to ensure quality).
This also creates a consistent, reproducible deployment process.&lt;/p&gt;
&lt;p&gt;GitHub Actions provides a straightforward way to implement this workflow.&lt;/p&gt;
&lt;p&gt;There are many ways to provide your apps with access to secrets during deployment.
The easiest is to store your deployment secrets in GitHub&amp;#39;s repository secrets.
For our dummy app, this includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SECRET_KEY_BASE&lt;/code&gt;: Your Phoenix application&amp;#39;s secret key&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DATABASE_URL&lt;/code&gt;: Connection string for your database&lt;/li&gt;
&lt;li&gt;&lt;code&gt;KAMAL_REGISTRY_PASSWORD&lt;/code&gt;: Password or token for your Docker registry&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SSH_PRIVATE_KEY&lt;/code&gt;: SSH key for accessing your deployment servers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, create a workflow file at &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;name: Deploy

on:
  push:
    branches: [main]

jobs:
  test:
    # Your existing test job
    runs-on: ubuntu-latest
    # ...

  lint:
    # Your existing lint job
    runs-on: ubuntu-latest
    # ...

  deploy:
    needs: [test, lint]
    runs-on: ubuntu-latest
    if: ${{ github.event_name == &amp;#39;push&amp;#39; &amp;amp;&amp;amp; github.ref_name == &amp;#39;main&amp;#39; }}
    timeout-minutes: 20
    env:
      DOCKER_BUILDKIT: 1
      VERSION: ${{ github.sha }}
      SECRET_KEY_BASE: ${{ secrets.SECRET_KEY_BASE }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
      KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}
    steps:
      - uses: actions/checkout@v4
      - name: Set up Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v3
      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true
      - name: Setup SSH
        uses: webfactory/ssh-agent@v0.9.1
        with:
          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
      - name: Deploy
        run: bundle exec kamal deploy --version=$VERSION
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This workflow does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Runs on every push to the main branch.&lt;/li&gt;
&lt;li&gt;Waits for tests and linting to pass before deploying.&lt;/li&gt;
&lt;li&gt;Sets up all necessary tools (such as Docker, Ruby, and SSH).&lt;/li&gt;
&lt;li&gt;Passes your secrets as environment variables to Kamal.&lt;/li&gt;
&lt;li&gt;Deploys using the Git commit SHA as the version tag.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;--version=$VERSION&lt;/code&gt; flag tells Kamal to tag your Docker image with the Git commit SHA, making each deployment uniquely identifiable and traceable back to a specific commit.&lt;/p&gt;
&lt;p&gt;There are several alternatives for managing secrets in this workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Environment Variables (shown above)&lt;/strong&gt;: The simplest approach, which uses GitHub secrets directly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1Password Integration&lt;/strong&gt;: If you use 1Password for team secret management, you can update the workflow to install 1Password CLI and modify your &lt;code&gt;.kamal/secrets&lt;/code&gt; file to fetch from 1Password.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other Secret Managers&lt;/strong&gt;: You can adapt the workflow to use Bitwarden, LastPass, or other supported secret managers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For larger teams, you might also want to consider setting up staging and production environments with separate workflows triggered by different branches or using GitHub environments for more controlled deployments.&lt;/p&gt;
&lt;p&gt;With this CI/CD integration, your development workflow becomes the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Develop features in branches.&lt;/li&gt;
&lt;li&gt;Open pull requests for review.&lt;/li&gt;
&lt;li&gt;Merge approved pull requests to main.&lt;/li&gt;
&lt;li&gt;GitHub Actions automatically tests, builds, and deploys your application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This fully automated pipeline gives you all the convenience of a PaaS while maintaining complete control over your infrastructure and deployment process — the best of both worlds.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Whether you&amp;#39;re deploying a simple Phoenix application or a complex distributed system, Kamal provides a solid foundation that grows with your needs.&lt;/p&gt;
&lt;p&gt;By following the steps outlined in this article, you&amp;#39;ll have a modern, efficient deployment workflow that lets you concentrate on what matters most: building great applications with Elixir and Phoenix.&lt;/p&gt;
&lt;p&gt;For those interested in exploring further, here are some topics to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-Role Deployments&lt;/strong&gt;: Set up separate web and background worker containers using Kamal&amp;#39;s multi-role support.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elixir Clustering&lt;/strong&gt;: Configure distributed Erlang clusters across multiple containers using &lt;code&gt;libcluster&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced Monitoring&lt;/strong&gt;: Integrate with application performance monitoring tools like &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;AppSignal for comprehensive monitoring of your Phoenix applications&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Scaling&lt;/strong&gt;: Implement horizontal scaling strategies for handling traffic spikes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backup and Disaster Recovery&lt;/strong&gt;: Establish robust backup procedures for your databases and application state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will discuss some of these topics in the next part of this series.
Until then, happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Set Up Tracing for Elixir Apps Using AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/06/03/how-to-set-up-tracing-for-elixir-apps-using-appsignal.html"/>
    <id>https://blog.appsignal.com/2025/06/03/how-to-set-up-tracing-for-elixir-apps-using-appsignal.html</id>
    <published>2025-06-03T00:00:00+00:00</published>
    <updated>2025-06-03T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">We&#039;ll set up tracing in your Elixir application using AppSignal.</summary>
    <content type="html">&lt;p&gt;Over time, web applications have evolved from simple request/response-based systems into complex, distributed ones with lots of moving parts. If something goes wrong (and you can be sure it will), finding the cause can be nearly impossible. But this need not be the case: enter tracing.&lt;/p&gt;
&lt;p&gt;Tracing refers to the process of collecting detailed information about the execution of requests within an application, including function calls, execution time, and other relevant data.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll learn what tracing is all about, including the benefits and challenges of tracing. In addition to this, we&amp;#39;ll look at distributed tracing and show you how to set up tracing using AppSignal for a Phoenix LiveView financial news tracker app.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, you&amp;#39;ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elixir and the Phoenix framework installed. You can &lt;a href=&quot;https://hexdocs.pm/phoenix/installation.html&quot;&gt;follow this guide&lt;/a&gt; to set them up.&lt;/li&gt;
&lt;li&gt;An Elixir application. For this tutorial, we&amp;#39;ll use the &lt;a href=&quot;https://github.com/iamaestimo/finance_news_fetcher_app&quot;&gt;Phoenix LiveView financial news tracker app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An AppSignal account. If you don&amp;#39;t have one, &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;you can sign up for a free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Some experience working with Elixir and the Phoenix framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that done, let&amp;#39;s learn what tracing is all about.&lt;/p&gt;
&lt;h2&gt;Understanding Tracing&lt;/h2&gt;
&lt;p&gt;Tracing is the process of collecting data during the runtime execution of an application. It gives you visibility into what an individual service (an internal module or function, an external integration, or a combination of all these) does as part of a request cycle. Essentially, the term &amp;quot;tracing&amp;quot; includes both &amp;quot;application tracing&amp;quot; and &amp;quot;distributed tracing&amp;quot;.&lt;/p&gt;
&lt;h3&gt;Application Tracing vs. Distributed Tracing&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Application tracing&lt;/em&gt; and &lt;em&gt;distributed tracing&lt;/em&gt; can be collectively termed as &amp;quot;tracing&amp;quot;. However, with application tracing, you follow the execution path of a request within an application or a single service. For example, tracing a user authentication flow that starts and completes within an application without calls to an external system is a good example of an application trace.&lt;/p&gt;
&lt;p&gt;But now imagine a distributed system where an app has to interact with external services. The news tracker application which we&amp;#39;ll use throughout this article is a perfect example of this.&lt;/p&gt;
&lt;p&gt;Here, a request crosses several service boundaries — from the app, through one or more background-job services, to the news-fetching API, then into a cache service that stores the fetched news items, and finally back to the user&amp;#39;s browser. Even though this example is simple, tracing such a request flow goes beyond what happens inside the app; it covers every service and system the request touches. This is what we mean by &amp;quot;distributed tracing&amp;quot;.&lt;/p&gt;
&lt;h2&gt;Why We Trace&lt;/h2&gt;
&lt;p&gt;Without tracing in place, it&amp;#39;s difficult to understand what is going on with your app, which ultimately makes it challenging to measure the impact that various issues have on the application.&lt;/p&gt;
&lt;p&gt;Here are some reasons why you might want to trace:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance analysis&lt;/strong&gt; - There are many factors that could affect the performance of an Elixir application, such as slow API calls, unoptimized database queries, network latency, and more. But if you have tracing in place, you can pinpoint the issues slowing down your app and fix them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Helping with debugging&lt;/strong&gt; - Using the example news tracker app, let&amp;#39;s say users submit tickets about not getting news updates on time. Is the problem the API, the database, the news cache, or a combination of all three? Without proper tracing, finding where the issues are coming from can become a real headache for app developers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auditing&lt;/strong&gt; - From a compliance standpoint, tracing can be used to check if your application is leaking any sensitive data (such as usernames or emails) in server logs and other places where this data should not be.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, there are other reasons why we trace, but we&amp;#39;ll leave it at that for now. Next, let&amp;#39;s see why you should use AppSignal for tracing your Elixir application.&lt;/p&gt;
&lt;h2&gt;Why Use AppSignal for Elixir?&lt;/h2&gt;
&lt;p&gt;AppSignal is an excellent application performance management tool with integrations for most modern languages and frameworks. &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;AppSignal offers out-of-the-box integration for pure Elixir and Phoenix apps&lt;/a&gt;; for other frameworks and packages, you can add integrations using &lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation.html&quot;&gt;custom instrumentation&lt;/a&gt;, which isn&amp;#39;t that difficult to set up.&lt;/p&gt;
&lt;h2&gt;The Elixir App&lt;/h2&gt;
&lt;p&gt;The application we&amp;#39;ll work with throughout this tutorial is a Phoenix LiveView app that showcases a real-world application. It&amp;#39;s a financial news tracker app that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fetches financial news from the AlphaVantage API&lt;/li&gt;
&lt;li&gt;Manages user-specific news topic preferences&lt;/li&gt;
&lt;li&gt;Delivers real-time updates via LiveView&lt;/li&gt;
&lt;li&gt;Uses background jobs to fetch data&lt;/li&gt;
&lt;li&gt;Implements a caching layer to improve performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the architecture of the app below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/news-tracker-flow.png&quot; alt=&quot;News tracker app architecture&quot;/&gt;&lt;/p&gt;
&lt;p&gt;This architecture is perfect for demonstrating both application and distributed tracing.&lt;/p&gt;
&lt;p&gt;In case you haven&amp;#39;t done so already, go ahead and fork the app from &lt;a href=&quot;https://github.com/iamaestimo/finance_news_fetcher_app&quot;&gt;this Github repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Installing the AppSignal Package&lt;/h2&gt;
&lt;p&gt;Open up &lt;code&gt;mix.exs&lt;/code&gt; and add the AppSignal package as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
...
defp deps do
    [
      ...
      {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.13&amp;quot;}
    ]
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, run &lt;code&gt;mix deps.get&lt;/code&gt; to add the package to the application, then run the command below to install it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix appsignal.install &amp;lt;YOUR API KEY HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After running the installer, you should be prompted for the name of the app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Validating Push API key: Valid! 🎉
What is your application&amp;#39;s name? [email_subscription_app]: Email Subscription App
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, you&amp;#39;ll need to choose the configuration method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;There are two methods of configuring AppSignal in your application.
  Option 1: Using a &amp;quot;config/appsignal.exs&amp;quot; file. (1)
  Option 2: Using system environment variables.  (2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Choose the option that suits you best, although the config file option makes it easier to &lt;a href=&quot;https://docs.appsignal.com/guides/configuration.html&quot;&gt;customize the configuration&lt;/a&gt; as you wish.&lt;/p&gt;
&lt;p&gt;Next, since we are working with Phoenix LiveView, we need to take some extra setup steps.&lt;/p&gt;
&lt;h3&gt;Adding AppSignal Phoenix Support&lt;/h3&gt;
&lt;p&gt;Support for Phoenix instrumentation comes in a separate package that depends on the main package we just installed. To add the Phoenix support package, add it to &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;defmodule FinanceNews.MixProject do
  ...
  defp deps do
    [
      ...
      {:appsignal, &amp;quot;~&amp;gt; 2.8&amp;quot;},
      {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add the LiveView telemetry integration in the app&amp;#39;s &lt;code&gt;application.ex&lt;/code&gt; file, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FinanceNews.Application do

  use Application

  def start(_type, _args) do
    Appsignal.Phoenix.LiveView.attach() # add this line
    children = [
      ...
    ]
    ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Tip: AppSignal offers two different ways to instrument live views, using an automatic handler or through manual instrumentation.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And with that, we have what we need to start tracing our app&amp;#39;s requests. But, before we move on to the actual implementation, it&amp;#39;s very important we understand the building blocks of tracing and the types of data we want to collect using our tracing setup.&lt;/p&gt;
&lt;h2&gt;The Building Blocks of Tracing&lt;/h2&gt;
&lt;p&gt;As we&amp;#39;ve already mentioned, tracing is about understanding the journey a request takes through a system. That said, a trace is fundamentally made up of several building blocks such as transactions and spans, trace context, sampling, and tags and attributes.&lt;/p&gt;
&lt;h3&gt;Transactions and Spans&lt;/h3&gt;
&lt;p&gt;A &amp;quot;transaction&amp;quot; represents a complete unit of work in the application. You can visualize this using the structure of a tree, where the root is the initial request and the branches (spans) are the individual operations that make up that request.&lt;/p&gt;
&lt;p&gt;A span contains information like the name of the operation, the start and end times of the operation, a list of events that took place during the operation, and more.&lt;/p&gt;
&lt;h3&gt;Trace Context&lt;/h3&gt;
&lt;p&gt;This is a very important concept in distributed tracing, since it defines the relationship between different parts of a transaction across different services and even across system boundaries. For example, and as you will soon see, when our news tracker app makes an API call to fetch the latest news updates, it&amp;#39;s a good idea to know what is going on before, during, and after the API call. This is what we mean by &amp;quot;trace context&amp;quot;.&lt;/p&gt;
&lt;p&gt;The diagram below illustrates this concept using our news tracker app:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/finance-news-tracker-trace-context.png&quot; alt=&quot;Finance news tracker app - trace context diagram&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Sampling&lt;/h3&gt;
&lt;p&gt;As much as we want visibility into every part of an application, it would be very costly and probably even negatively impact your app&amp;#39;s performance. At some point, you&amp;#39;ll have to decide what to trace and what to ignore. This becomes especially important in distributed systems where requests can go through complex transactions and cross many service boundaries. Sampling is the art of choosing representative transactions that will provide the most value to the tracing activity.&lt;/p&gt;
&lt;h3&gt;Tags and Attributes&lt;/h3&gt;
&lt;p&gt;Tags and attributes are descriptive pieces of information you use to add context to your traces.&lt;/p&gt;
&lt;h2&gt;What to Trace vs. What to Ignore&lt;/h2&gt;
&lt;p&gt;When deciding where to set up traces in your application, understanding what data to collect can be the difference between an effective and ineffective trace implementation.&lt;/p&gt;
&lt;p&gt;With that in mind, here are some valuable types of tracing data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Request/response data&lt;/strong&gt; - In the example app we&amp;#39;re using, having visibility into how various requests and responses are happening is very valuable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance metrics&lt;/strong&gt; - For example, it would be good to know how long a LiveView render of the latest news articles takes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Errors&lt;/strong&gt; - If an error occurs (let&amp;#39;s say when fetching news items from the API), it is valuable to know how the error started and progressed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom data&lt;/strong&gt; - One of the benefits of using a tool like AppSignal is the ability to use custom instrumentation to capture data that&amp;#39;s unique to your application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we know what data we should collect using a tracing setup, let&amp;#39;s implement it, starting with basic tracing, before moving on to more advanced tracing methods later.&lt;/p&gt;
&lt;h2&gt;Implementing Tracing&lt;/h2&gt;
&lt;p&gt;To get started with tracing, we need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set up a data capture layer using instrumentation.&lt;/li&gt;
&lt;li&gt;Send the tracing data to a third-party visualization system.&lt;/li&gt;
&lt;li&gt;Analyze the data for further action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since we are using the AppSignal library for Phoenix/Elixir, we get the first two without much effort on our part. The last bit is on us completely.&lt;/p&gt;
&lt;h2&gt;Tracing Web Transactions&lt;/h2&gt;
&lt;p&gt;In a Phoenix application, web transactions are the entry point of user interactions with our application, and will often be the trigger for subsequent and more advanced transactions later on.&lt;/p&gt;
&lt;p&gt;Using our example application, we can break down a web transaction as shown below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Initial request for information&lt;/li&gt;
&lt;li&gt;Controller and LiveView actions&lt;/li&gt;
&lt;li&gt;Database queries&lt;/li&gt;
&lt;li&gt;Rendering views&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To see how these are represented on the AppSignal dashboard, consider the &lt;code&gt;handle_event/3&lt;/code&gt; &lt;code&gt;&amp;quot;save_topics&amp;quot;&lt;/code&gt; function below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/finance_news_web/live/topic_live.ex

defmodule FinanceNewsWeb.TopicLive do
  ...

  def handle_event(&amp;quot;save_topics&amp;quot;, _, socket) do
    user = socket.assigns.current_user
    topics = MapSet.to_list(socket.assigns.selected_topics)

    case Topics.update_user_topics(user, topics) do
      {:ok, _} -&amp;gt;
        {:noreply, push_navigate(socket, to: ~p&amp;quot;/feed&amp;quot;)}

      {:error, _} -&amp;gt;
        {:noreply, assign(socket, error_message: &amp;quot;Failed to save topics. Please try again.&amp;quot;)}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From this code snippet, you can see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An interaction with the database to fetch the currently logged-in user&lt;/li&gt;
&lt;li&gt;Another interaction with the database to fetch or update the user&amp;#39;s selected topics&lt;/li&gt;
&lt;li&gt;Rendering the FeedLive LiveView or displaying an error message in case something goes wrong&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A request that makes use of this function will be traced and represented on your dashboard in AppSignal, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/finance-news-app-handle-event-trace-sample.png&quot; alt=&quot;Trace sample for the handle event - Finance news tracker app&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The trace shows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The name of the event&lt;/li&gt;
&lt;li&gt;A breakdown of the sample showing the time taken by the request while interacting with different services in the app. In this case, the Ecto transaction takes the most amount of time compared to the LiveView render.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But what does this really tell us? Or, put another way, how does this information help us?&lt;/p&gt;
&lt;h3&gt;Analyzing the Results&lt;/h3&gt;
&lt;p&gt;One use case for such trace data is to help you establish your app&amp;#39;s baseline performance. What this means is that, by collecting such data over time, you will soon establish what is acceptable versus what is not in terms of performance.&lt;/p&gt;
&lt;p&gt;For example, over time, you might discover topic updates take on average 20-30ms to load, so if you come across trace samples that show loading times of 50ms+, you would know something is amiss. You can then put performance alerts in place, with a setup that uses AppSignal&amp;#39;s custom instrumentation, as below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/finance_news_web/live/topic_live.ex
defmodule FinanceNewsWeb.TopicLive do
  ...
  def handle_event(&amp;quot;save_topics&amp;quot;, _, socket) do
    Appsignal.instrument(&amp;quot;Topics.save_topics&amp;quot;, fn -&amp;gt;
      user = socket.assigns.current_user
      topics = MapSet.to_list(socket.assigns.selected_topics)

      case Topics.update_user_topics(user, topics) do
        {:ok, _} -&amp;gt;
          {:noreply, push_navigate(socket, to: ~p&amp;quot;/feed&amp;quot;)}

        {:error, _} -&amp;gt;
          {:noreply, assign(socket, error_message: &amp;quot;Failed to save topics. Please try again.&amp;quot;)}
      end
    end)
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let&amp;#39;s look at a more advanced example where we trace an external service.&lt;/p&gt;
&lt;h2&gt;Tracing External Services&lt;/h2&gt;
&lt;p&gt;You&amp;#39;ll often find external services to be the most unpredictable part of any application. Such services can be integral to your app&amp;#39;s functioning, but since you don&amp;#39;t have 100% control, you&amp;#39;ll find that they can fail, time out, or become slow without warning.&lt;/p&gt;
&lt;p&gt;You can see that sourcing the latest finance news items is key to the functioning of our financial news tracker app. Yet this part of the app completely relies on an external service, the Alpha Vantage API.&lt;/p&gt;
&lt;p&gt;As the API is important to our app&amp;#39;s functioning, let&amp;#39;s see how we can implement tracing for such an external service.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: AppSignal offers automatic instrumentation for HTTP libraries like Finch (we&amp;#39;re using Finch in the news tracker app), so there&amp;#39;s no need to add any instrumentation for now. But if you need a custom, more detailed trace, go ahead and use a custom instrumentation.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The results of tracing external service requests are shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/finch-tracing-listing.png&quot; alt=&quot;Finch tracing - trace listings&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Details of the trace are also shown below (note how AppSignal conveniently places such traces under the appropriate &amp;quot;background&amp;quot; namespace):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-06/finch-tracing-details.png&quot; alt=&quot;Finch tracing - trace details&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we learned that tracing goes far beyond simple error tracking. By using various examples related to our financial news tracker application, we&amp;#39;ve seen how proper instrumentation provides complete request visibility, performance insights, and even deep information on errors.&lt;/p&gt;
&lt;p&gt;With tracing in place, you&amp;#39;ll have much greater visibility into how requests flow through your system, empowering you to see bottlenecks and optimize the performance and reliability of your Elixir apps. Combine this with the intuitive dashboards provided by AppSignal, and you have everything you need to professionally run an Elixir application in production.&lt;/p&gt;
&lt;p&gt;Happy tracing!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Ecto for Elixir Monitoring with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/05/13/an-introduction-to-ecto-for-elixir-monitoring-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2025/05/13/an-introduction-to-ecto-for-elixir-monitoring-with-appsignal.html</id>
    <published>2025-05-13T00:00:00+00:00</published>
    <updated>2025-05-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s set up Ecto monitoring in your Elixir application using AppSignal.</summary>
    <content type="html">&lt;p&gt;Database performance can make or break your Elixir application. While Ecto provides a powerful toolkit for database interactions, understanding how these operations perform in production is critical. Whether you&amp;#39;re dealing with slow queries, connection pool issues, or mysterious N+1 problems, the ability to effectively monitor and optimize your database operations can be the difference between a sluggish application and one that delights your users.&lt;/p&gt;
&lt;p&gt;In this introductory guide, you&amp;#39;ll learn how to implement Ecto monitoring using AppSignal. We&amp;#39;ll explore some basic monitoring strategies that will help you identify, diagnose, and resolve database performance issues before they impact your users. By the end of this article, you&amp;#39;ll understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to set up Ecto monitoring in your Elixir application&lt;/li&gt;
&lt;li&gt;Which key metrics matter most for database performance&lt;/li&gt;
&lt;li&gt;How to detect and resolve common Ecto performance bottlenecks&lt;/li&gt;
&lt;li&gt;Best practices for setting up alerts and dashboards&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before we get started, let&amp;#39;s see what you&amp;#39;ll need to follow along with this tutorial.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;An AppSignal account. You can &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;sign up for a free trial&lt;/a&gt; if you don&amp;#39;t have one.&lt;/li&gt;
&lt;li&gt;Elixir, Phoenix, and PostgreSQL installed&lt;/li&gt;
&lt;li&gt;A Phoenix application to follow along with. &lt;a href=&quot;https://github.com/iamaestimo/phoenix_blog_tutorial_app&quot;&gt;Fork the Phoenix blog app&lt;/a&gt; we&amp;#39;ll be using for the tutorial if you don&amp;#39;t have one ready.&lt;/li&gt;
&lt;li&gt;Some experience with Elixir and the Phoenix framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What Is Ecto for Elixir?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.html&quot;&gt;Ecto&lt;/a&gt; is a toolkit that gives you a seamless way to interact with different databases in Elixir applications. You could be wondering why I use the term &amp;quot;toolkit&amp;quot; versus the more common &amp;quot;object-relational mapper&amp;quot; (ORM). Ecto does map database tables into Elixir structs, but more than that, it also includes some distinct features that make it much more than an ORM:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Query&lt;/strong&gt; - Ecto includes a macro-based domain-specific language (DSL) to compose powerful queries for fetching data from a database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schema&lt;/strong&gt; - The module gives you all you need to build schemas (Elixir structs that map directly to your app&amp;#39;s database tables).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Changeset&lt;/strong&gt; - Ecto&amp;#39;s changeset is responsible for ensuring data integrity in your application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repo&lt;/strong&gt; - this is the main interface that wraps around and interacts with your app&amp;#39;s database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Because Ecto is composed of various modules for interacting with databases, there is a larger surface area where things can go wrong, making effective monitoring essential.&lt;/p&gt;
&lt;p&gt;Head over to the &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.html&quot;&gt;Ecto documentation&lt;/a&gt; to learn more. For now, let&amp;#39;s move on and learn how to integrate AppSignal with an Elixir app.&lt;/p&gt;
&lt;h2&gt;Integrating AppSignal with an Elixir Application&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll be using a simple Phoenix blog application. Our first step is to add the AppSignal package like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs

def deps do
  [
    {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;mix deps.get&lt;/code&gt; to install the package, followed by the AppSignal package installer command &lt;code&gt;mix appsignal.install &amp;lt;YOUR PUSH API KEY&amp;gt;&lt;/code&gt;. This should give you a few options to customize how the package will be installed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Validating Push API key: Valid! 🎉
What is your application&amp;#39;s name? [email_subscription_app]: Blog App
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Choose the AppSignal configuration method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;There are two methods of configuring AppSignal in your application.
  Option 1: Using a &amp;quot;config/appsignal.exs&amp;quot; file. (1)
  Option 2: Using system environment variables.  (2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Decide what will work for you, but the config file option makes it easier to &lt;a href=&quot;https://docs.appsignal.com/guides/configuration.html&quot;&gt;customize the configuration&lt;/a&gt; the way you&amp;#39;d like.&lt;/p&gt;
&lt;p&gt;One thing to take note of is that AppSignal will offer automatic instrumentation of Ecto queries as long as your app&amp;#39;s OTP name matches what is configured in the AppSignal config file, as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/appsignal.exs

import Config

config :appsignal, :config,
  otp_app: :blog_phoenix, # the otp name here...
  name: &amp;quot;blog_phoenix&amp;quot;,
  push_api_key: &amp;quot;YOUR PUSH API KEY&amp;quot;,
  env: Mix.env
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/dev.exs

config :blog_phoenix, BlogPhoenix.Repo,
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if everything goes as planned, your app should start sending data to AppSignal in a few minutes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/successful-appsignal-integration.png&quot; alt=&quot;Successful AppSignal Integration&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Next up, let&amp;#39;s briefly go through the importance of monitoring Ecto.&lt;/p&gt;
&lt;h2&gt;Why Monitoring Ecto Is Crucial for Application Performance&lt;/h2&gt;
&lt;p&gt;Just like other parts of your application, your database and the Ecto interface wrapped around it require constant observation to detect issues early and to maintain good performance.&lt;/p&gt;
&lt;p&gt;Without monitoring, performance bottlenecks can go unnoticed until they end up directly affecting your app&amp;#39;s users. By setting up a well-structured monitoring system for Ecto, you are able to see issues before they grow into serious problems.&lt;/p&gt;
&lt;p&gt;But in order to fix the issues that would end up affecting Ecto&amp;#39;s performance, you must set up monitoring for the right metrics.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Monitoring Key Ecto Metrics&lt;/h2&gt;
&lt;p&gt;Focusing on key metrics will give you insights into the efficiency and responsiveness of your database queries, allowing you to identify bottlenecks and optimize database operations.&lt;/p&gt;
&lt;p&gt;Below are a few key &lt;a href=&quot;https://www.appsignal.com/elixir/ecto-monitoring&quot;&gt;Ecto metrics&lt;/a&gt; that are good candidates for monitoring in AppSignal.&lt;/p&gt;
&lt;h2&gt;Query Execution Time&lt;/h2&gt;
&lt;p&gt;Tracking how long queries take to execute is a very important metric. Queries that are not properly optimized will affect the performance of your database.&lt;/p&gt;
&lt;p&gt;For example, in our blog application, the query for fetching all blog posts used by the controller&amp;#39;s index method is shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/blog_phoenix/blog.ex

defmodule BlogPhoenix.Blog do
  ...

  def list_posts do
    Repo.all(Post)
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this query is not optimized in any way. To test it out, I seeded the app&amp;#39;s database with two thousand posts, and then I made a request for the posts index view.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see how this was instrumented and displayed on the AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/slow-query-index-action.png&quot; alt=&quot;Index Action - Slow Query Dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As expected, the unoptimized query led to a high-impact event on Ecto, which was captured in detail on the dashboard.&lt;/p&gt;
&lt;p&gt;Later on, we&amp;#39;ll look at a few ways to optimize queries, but for now, let&amp;#39;s examine another metric that warrants monitoring: resource consumption.&lt;/p&gt;
&lt;h2&gt;Resource Consumption&lt;/h2&gt;
&lt;p&gt;Although not directly related to Ecto, it&amp;#39;s likely your app will be hosted on a server. While it&amp;#39;s hosted there, it&amp;#39;s possible that whatever might affect the server&amp;#39;s resources (such as processor speed, database read/writes, and memory) will also affect Ecto&amp;#39;s performance.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/host-monitoring-dashboards.png&quot; alt=&quot;Host Monitoring Dashboards&quot;/&gt;&lt;/p&gt;
&lt;p&gt;For example, something totally unrelated to your app could cause the server to experience high disk read/writes. If your app performs a large number of database transactions at the same time, then it&amp;#39;s possible that Ecto&amp;#39;s performance will be affected. Being able to see the server&amp;#39;s performance metrics provides an extra set of important insights that could help you optimize your application.&lt;/p&gt;
&lt;p&gt;Next up is throughput.&lt;/p&gt;
&lt;h2&gt;Throughput&lt;/h2&gt;
&lt;p&gt;Throughput refers to the number of transactions completed within a given timeframe. The higher your app&amp;#39;s throughput numbers, the better.&lt;/p&gt;
&lt;p&gt;In the context of AppSignal monitoring, it&amp;#39;s good to note that &amp;quot;throughput&amp;quot; does not show how many transactions or users your app can support as a whole. Rather, it is a snapshot into the number of transactions Ecto can process for a particular event:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/ecto-throughput.png&quot; alt=&quot;Ecto Throughput&quot;/&gt;&lt;/p&gt;
&lt;p&gt;So far, the instrumentation for the metrics we have looked at is provided automatically by the AppSignal package. However, there are other metrics that are just as important but which would need some extra work on our part.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at how to set up custom instrumentation for a particularly interesting metric: database connection pools.&lt;/p&gt;
&lt;h2&gt;Database Connection Pools&lt;/h2&gt;
&lt;p&gt;The connection pool size is an important metric to monitor because it directly affects Ecto&amp;#39;s performance and therefore the overall performance of your app.&lt;/p&gt;
&lt;p&gt;Each database connection consumes a bit of your server&amp;#39;s resources (server processor time, memory, and so on). Too many connections will overload your server, directly affecting the performance of your app. But then again, having too few will mean that new requests have to wait for connections to become available, which also affects your app&amp;#39;s performance.&lt;/p&gt;
&lt;p&gt;As such, it becomes necessary to monitor your app&amp;#39;s database pool size to ensure optimal performance.&lt;/p&gt;
&lt;p&gt;By default, AppSignal will not offer automatic instrumentation for this metric, but that doesn&amp;#39;t mean we cannot set up custom instrumentation for it. Let&amp;#39;s do that next.&lt;/p&gt;
&lt;h3&gt;Setting up Ecto Custom Instrumentation&lt;/h3&gt;
&lt;p&gt;The first step is to set up a dedicated &lt;code&gt;PoolMonitor&lt;/code&gt; Genserver to monitor the database pool size and collect metrics regularly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/blog_phoenix/pool_monitor.ex

defmodule BlogPhoenix.PoolMonitor do
  use GenServer
  require Logger
  alias Ecto.Adapters.SQL

  @spec start_link(any()) :: GenServer.on_start()
  def start_link(_opts) do
    GenServer.start_link(__MODULE__, %{})
  end

  @impl true
  def init(state) do
    schedule_metrics_collection()
    {:ok, state}
  end

  @impl true
  def handle_info(:collect_metrics, state) do
    _ = collect_pool_metrics()
    schedule_metrics_collection()
    {:noreply, state}
  end

  defp schedule_metrics_collection do
    Process.send_after(self(), :collect_metrics, :timer.seconds(15))
  end

  @spec collect_pool_metrics() :: :ok
  defp collect_pool_metrics do
    pool_size = BlogPhoenix.Repo.config[:pool_size]

    # Get current connection status using a SQL query
    used_connections =
      case SQL.query(BlogPhoenix.Repo, &amp;quot;SELECT count(*) FROM pg_stat_activity WHERE datname = current_database()&amp;quot;) do
        {:ok, %{rows: [[count]]}} -&amp;gt; count
        _ -&amp;gt; 0
      end

    # Send metrics to AppSignal
    :ok = Appsignal.set_gauge(
      &amp;quot;database.pool.size_total&amp;quot;,
      pool_size,
      %{repo: &amp;quot;BlogPhoenix.Repo&amp;quot;}
    )

    :ok = Appsignal.set_gauge(
      &amp;quot;database.pool.used_connections&amp;quot;,
      used_connections,
      %{repo: &amp;quot;BlogPhoenix.Repo&amp;quot;}
    )

    # Calculate and send usage percentage
    usage_percentage = (used_connections / pool_size) * 100
    :ok = Appsignal.set_gauge(
      &amp;quot;database.pool.usage_percentage&amp;quot;,
      usage_percentage,
      %{repo: &amp;quot;BlogPhoenix.Repo&amp;quot;}
    )

    Logger.debug(&amp;quot;Pool metrics collected: size=#{pool_size}, used=#{used_connections}, usage=#{usage_percentage}%&amp;quot;)
    :ok
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without explaining everything the code is doing, let&amp;#39;s highlight some parts of it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We make use of &lt;code&gt;Ecto.Adapters.SQL.query/4&lt;/code&gt; to safely execute raw SQL queries using Ecto. This way, we can fetch the database connection pool without interacting with the PostgreSQL database directly, which is the recommended way to interact with the database.&lt;/li&gt;
&lt;li&gt;The SQL query uses the PostgreSQL-specific &lt;code&gt;pg_stat_activity&lt;/code&gt; to return the number of connection pools. You can read more about the &lt;a href=&quot;https://www.PostgreSQL.org/docs/current/monitoring-stats.html&quot;&gt;PostgreSQL cumulative statistics system from the documentation&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, we ensure this new GenServer is included in the supervision tree:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/blog_phoenix/application.ex

defmodule BlogPhoenix.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      BlogPhoenixWeb.Telemetry,
      BlogPhoenix.Repo,
      BlogPhoenix.PoolMonitor # new Genserver
      ...

      opts = [strategy: :one_for_one, name: BlogPhoenix.Supervisor]
      Supervisor.start_link(children, opts)
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, we are now ready to visualize the metrics on the AppSignal dashboard.&lt;/p&gt;
&lt;h2&gt;Setting Up Custom Dashboards&lt;/h2&gt;
&lt;p&gt;As you might have guessed, since we&amp;#39;ve built a custom instrumentation, we&amp;#39;ll need to set up custom dashboards to view the metrics.&lt;/p&gt;
&lt;p&gt;Start by clicking on the &amp;quot;Add dashboard&amp;quot; button on the left-side menu, then the &amp;quot;Create a dashboard&amp;quot; button on the resulting screen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/custom-dashboards-1.png&quot; alt=&quot;Create Custom Dashboards - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Then give your dashboard an appropriate name and description:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/custom-dashboards-2.png&quot; alt=&quot;Create Custom Dashboards - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Once your new custom dashboard is created, the next step is to add custom graphs.&lt;/p&gt;
&lt;h3&gt;Adding Custom Graphs&lt;/h3&gt;
&lt;p&gt;Click on the &amp;quot;add new graph&amp;quot; link:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/adding-custom-graph-1.png&quot; alt=&quot;Adding Custom Graph - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Provide the relevant information for your graph, including a title, description, etc. You can read more in &lt;a href=&quot;https://docs.appsignal.com/metrics/custom.html&quot;&gt;AppSignal&amp;#39;s custom metrics documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a closer look at the metric labeled &lt;em&gt;number 7&lt;/em&gt; on the screenshot. Remember the custom gauges we set up in the &lt;code&gt;PoolMonitor&lt;/code&gt; GenServer code above?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...

  :ok = Appsignal.set_gauge(
      &amp;quot;database.pool.size_total&amp;quot;,
      pool_size,
      %{repo: &amp;quot;BlogPhoenix.Repo&amp;quot;}
    )
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to pull and visualize these using the custom graph. In my case, I chose &lt;code&gt;database.pool.size_total&lt;/code&gt;, which results in the dashboard you can see below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-04/adding-custom-graph-2.png&quot; alt=&quot;Adding Custom Graph - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we learned how to monitor the Elixir database toolkit, Ecto. We&amp;#39;ve seen the importance of monitoring Ecto and how it affects overall app performance. Additionally, we went through how AppSignal offers automatic monitoring for various metrics. We even learned how to set up custom instrumentation for metrics that aren&amp;#39;t automatically covered.&lt;/p&gt;
&lt;p&gt;This was more of an introductory tutorial. In part two of this series, we&amp;#39;ll dive deeper into how to establish baseline metrics, set up alerts, notifications, and robust exception monitoring for Ecto.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Advanced Dialyzer Usage in Elixir: Types and Troubleshooting</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/04/01/advanced-dialyzer-usage-in-elixir-types-and-troubleshooting.html"/>
    <id>https://blog.appsignal.com/2025/04/01/advanced-dialyzer-usage-in-elixir-types-and-troubleshooting.html</id>
    <published>2025-04-01T00:00:00+00:00</published>
    <updated>2025-04-01T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of this two-part series, we&#039;ll look at more advanced Dialyzer use cases.</summary>
    <content type="html">&lt;p&gt;In our previous post, we covered the basics of setting up and using Dialyzer in your Elixir project.
Now, let&amp;#39;s dive deeper into advanced type specifications, complex warning patterns, and troubleshooting techniques that will help you make the most of Dialyzer.&lt;/p&gt;
&lt;h2&gt;Advanced Type Annotations&lt;/h2&gt;
&lt;p&gt;Advanced type annotations include opaque types, recursive types, and generic types. Let&amp;#39;s start by looking at opaque types.&lt;/p&gt;
&lt;h3&gt;Opaque Types&lt;/h3&gt;
&lt;p&gt;Opaque types enforce data abstraction by hiding a type&amp;#39;s internal structure from external modules.
This ensures that any data manipulation occurs solely through a module&amp;#39;s public API, thereby safeguarding the integrity of the data.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s create a &lt;code&gt;Counter&lt;/code&gt; module that uses an opaque type to hide its internal structure.
This allows us to change the implementation details later without affecting code that uses the module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Counter do
  @opaque t :: %__MODULE__{
    value: non_neg_integer(),
    max: pos_integer()
  }
  defstruct [:value, :max]

  @spec new(pos_integer()) :: t()
  def new(max), do: %__MODULE__{value: 0, max: max}

  @spec increment(t()) :: {:ok, t()} | {:error, :max_reached}
  def increment(%__MODULE__{value: value, max: max} = counter) when value &amp;lt; max do
    {:ok, %{counter | value: value + 1}}
  end
  def increment(%__MODULE__{}), do: {:error, :max_reached}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By marking the type as &lt;code&gt;@opaque&lt;/code&gt;, we ensure that other modules can only interact with our counter through the &lt;code&gt;new/1&lt;/code&gt; and &lt;code&gt;increment/1&lt;/code&gt; functions, preventing direct manipulation of the struct fields.&lt;/p&gt;
&lt;h3&gt;Recursive Types&lt;/h3&gt;
&lt;p&gt;Recursive types allow you to define complex, self-referential data structures such as trees or nested expressions.
They are particularly useful for modeling hierarchical data and for tasks like evaluating an abstract syntax tree in interpreters or compilers.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of using recursive types to define and evaluate a simple arithmetic expression tree:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule AST do
  @type node ::
    {:binary, node(), :+| :- | :* | :/, node()} |
    {:unary, :- | :+, node()} |
    {:number, number()}

  @spec evaluate(node()) :: number()
  def evaluate({:binary, left, op, right}) do
    apply_op(op, evaluate(left), evaluate(right))
  end
  def evaluate({:unary, op, expr}), do: apply_unary(op, evaluate(expr))
  def evaluate({:number, n}), do: n
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By defining the &lt;code&gt;node()&lt;/code&gt; type recursively, we can represent expressions of arbitrary complexity while maintaining type safety.
This helps catch errors like malformed expressions at compile-time rather than runtime.&lt;/p&gt;
&lt;h3&gt;Generic Types&lt;/h3&gt;
&lt;p&gt;Generic types help create flexible and reusable code by allowing types to be parameterized.
This enables you to write functions and structures that can work with various data types while still ensuring type safety.
They&amp;#39;re particularly valuable when implementing common patterns like result types, option types, or collection operations.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at a practical example using generic types to create a type-safe result wrapper:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Result do
  @type t(ok, error) :: {:ok, ok} | {:error, error}

  @spec map(t(a, e), (a -&amp;gt; b)) :: t(b, e) when a: var, b: var, e: var
  def map({:ok, value}, fun), do: {:ok, fun.(value)}
  def map({:error, _} = error, _fun), do: error
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;t(ok, error)&lt;/code&gt; type allows us to specify both the success and error types, making it impossible to mix incompatible values.
This pattern is incredibly useful for error handling and data transformation pipelines, ensuring type safety throughout the entire chain of operations.&lt;/p&gt;
&lt;h2&gt;Advanced Warning Patterns in Elixir&lt;/h2&gt;
&lt;p&gt;We already examined some common warnings in the first part of this series.
Let&amp;#39;s examine some of the more complex warning patterns you might encounter, starting with invalid contracts.&lt;/p&gt;
&lt;h3&gt;1. Invalid Contract&lt;/h3&gt;
&lt;p&gt;In this example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule StringHelper do
  @spec valid_format?(String.t()) :: :ok | :error
  def valid_format?(str) do
    pattern = ~r/^[A-Z][a-z]+(-[A-Z][a-z]+)*$/
    Regex.match?(pattern, str)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This warning occurs because the function returns a boolean (&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;) from &lt;code&gt;Regex.match?/2&lt;/code&gt;, but the typespec promises &lt;code&gt;:ok | :error&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/example.ex:17:invalid_contract Invalid type specification for function valid_format?.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Always ensure your typespec matches the actual return value.
The correct typespec should be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@spec valid_format?(String.t()) :: boolean()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Function Application Arguments&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s look at a function application argument:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Calculator do
  @spec sum(list(integer())) :: integer()
  def sum(numbers), do: Enum.sum(numbers)

  def process() do
    sum([&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;3&amp;quot;])  # Passing strings instead of integers
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;This error occurs when passing arguments of incorrect types to functions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/calculator.ex:6: The function call will not succeed.
Calculator.sum([&amp;lt;&amp;lt;49&amp;gt;&amp;gt;, &amp;lt;&amp;lt;50&amp;gt;&amp;gt;, &amp;lt;&amp;lt;51&amp;gt;&amp;gt;])
breaks the contract
([integer()]) :: integer()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Always ensure the arguments match the function&amp;#39;s typespec.
Here, converting strings to integers first would fix the issue.&lt;/p&gt;
&lt;h3&gt;3. Opaque Type Mismatch&lt;/h3&gt;
&lt;p&gt;Opaque types are a powerful feature in Elixir, enabling true data abstraction.
When you mark a type as &lt;code&gt;@opaque&lt;/code&gt;, you tell Dialyzer that the type&amp;#39;s internal structure should only be visible within the module that defines it.
This is particularly useful for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encapsulation&lt;/strong&gt;: Hiding implementation details from other modules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Integrity&lt;/strong&gt;: Ensuring data is only modified through your module&amp;#39;s API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Stability&lt;/strong&gt;: Changing internal representations without affecting external code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: Preventing sensitive data from being directly manipulated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s look at an example where we create a secure storage module that encrypts data, but a consumer module incorrectly tries to manipulate the encrypted data directly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SecureStorage do
  @opaque encrypted_data :: binary()

  @spec encrypt(String.t()) :: encrypted_data()
  def encrypt(data), do: Base.encode64(data)

  # Wrong: Another module trying to manipulate opaque type directly
  defmodule Consumer do
    def process_data(data) do
      SecureStorage.encrypt(&amp;quot;secret&amp;quot;)
      |&amp;gt; String.split(&amp;quot;,&amp;quot;)  # Error: Treating opaque type as string
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leading to this error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/secure_storage.ex:10:21:call_with_opaque
The call String.split(&amp;#39;Elixir.SecureStorage&amp;#39;:encrypted_data(),&amp;lt;&amp;lt;44&amp;gt;&amp;gt;) contains an opaque term in 1st argument when terms of different types are expected in these positions}.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Opaque types should only be manipulated by the module that defines them.
Instead of allowing direct manipulation, provide public functions to interact with opaque types.&lt;/p&gt;
&lt;h3&gt;4. Range Errors&lt;/h3&gt;
&lt;p&gt;Dialyzer detects two types of range errors — missing range and extra range.&lt;/p&gt;
&lt;p&gt;Missing range is when a typespec contains a larger range than what a function may return.
For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
  @spec ok(boolean()) :: :ok
  def ok(true), do: :ok
  def ok(false), do: :error
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So you&amp;#39;ll see:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/example.ex:missing_range
The type specification is missing types returned by function.

Function:
Example.ok/1

Type specification return types:
:ok

Missing from spec:
:error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, extra range is when the typespec contains a larger range than what a function may return.
For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
  @spec error(boolean()) :: :ok | :error
  def error(_book), do: :error
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You get the error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/example.ex:extra_range
The type specification has too many types for the function.

Function:
Example.error/1

Extra type:
:ok

Success typing:
:error
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tips for Working with Dialyzer in Elixir&lt;/h3&gt;
&lt;p&gt;Dialyzer can sometimes feel daunting, especially if you are just starting with it.
Here are some tips for when you are just beginning your Dialyzer journey:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start with broader types and narrow them as needed&lt;/strong&gt;
This approach allows you to catch obvious errors without being overly restrictive, giving you room to adapt your types as you understand your codebase better.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use built-in types like &lt;code&gt;term()&lt;/code&gt; sparingly&lt;/strong&gt;
Although &lt;code&gt;term()&lt;/code&gt; is very generic, relying on more specific types improves type safety and makes your code self-documenting, helping others understand the expected data shapes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Consider using &lt;code&gt;TypeCheck&lt;/code&gt; alongside Dialyzer for runtime type checking during development&lt;/strong&gt;
Runtime checks with &lt;code&gt;TypeCheck&lt;/code&gt; can complement Dialyzer&amp;#39;s static analysis, catching errors that might slip through and providing immediate feedback during development.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Remember that Dialyzer is success typing — it only reports errors it&amp;#39;s certain about&lt;/strong&gt;
This means Dialyzer might miss some potential issues.
It&amp;#39;s important to combine its analysis with thorough testing and code reviews for comprehensive error detection.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Troubleshooting Dialyzer&lt;/h2&gt;
&lt;p&gt;While Dialyzer is a powerful tool, you might encounter some challenges when first integrating it into your workflow.
When you encounter Dialyzer warnings that are difficult to understand, there are several strategies you can employ. Let&amp;#39;s look at output control first.&lt;/p&gt;
&lt;h3&gt;Output control&lt;/h3&gt;
&lt;p&gt;Dialyzer includes verbose information by default.
You can control the output level:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix dialyzer --quiet-with-result # Print only the final results
mix dialyzer --quiet             # No output unless there are errors
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Incremental Analysis&lt;/h3&gt;
&lt;p&gt;For large projects, it can sometimes be helpful to analyze one module at a time.
This can be configured inside &lt;code&gt;mix.exs&lt;/code&gt; by specifying &lt;code&gt;dialyzer.paths&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
def project do
  [
    dialyzer: [
      paths: [&amp;quot;lib/specific_module.ex&amp;quot;]
    ]
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Configuration Tweaks&lt;/h3&gt;
&lt;p&gt;Dialyzer&amp;#39;s behavior can be fine-tuned through various configuration options, particularly around Persistent Lookup Table (PLT) management:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
def project do
  [
    dialyzer: [
      plt_add_deps: :apps_direct,
      plt_add_apps: [:mix, :ex_unit],
      plt_ignore_apps: [:mock]
    ]
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s what each configuration option does:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PLT Dependencies&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:plt_add_deps&lt;/code&gt; controls how dependencies are added to your PLT:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:app_tree&lt;/code&gt; (default) - Includes all transitive OTP dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:apps_direct&lt;/code&gt; - Only includes direct OTP dependencies, so is useful for faster analysis&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:plt_add_apps&lt;/code&gt; lets you include additional applications beyond your direct dependencies&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:plt_ignore_apps&lt;/code&gt; helps exclude specific applications from analysis&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;:plt_apps&lt;/code&gt; allows you to specify an exact list of applications, replacing the default list&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PLT File Management&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:plt_core_path&lt;/code&gt; defines where PLT files are stored&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:plt_file&lt;/code&gt; specifies the PLT file path and options&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Pro tip&lt;/strong&gt;: For team projects, consider storing PLT files in a shared location to speed up analysis across the team.&lt;/p&gt;
&lt;p&gt;Next up we&amp;#39;ll look at ignoring warnings.&lt;/p&gt;
&lt;h3&gt;Ignoring Warnings&lt;/h3&gt;
&lt;p&gt;While it&amp;#39;s best to fix all warnings, sometimes you need to suppress specific warnings, especially when migrating a large codebase to use Dialyzer.
The &lt;code&gt;ignore_warnings&lt;/code&gt; configuration helps manage this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate a list of current warnings in the ignore file format:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix dialyzer --format ignore_file
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Create &lt;code&gt;.dialyzer_ignore.exs&lt;/code&gt; with the warnings you want to ignore:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[
  {&amp;quot;lib/example.ex&amp;quot;, :call},
  {&amp;quot;lib/secure_storage.ex&amp;quot;, :call_with_opaque}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Configure Dialyzer to use this file:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
def project do
  [
    dialyzer: [
      ignore_warnings: &amp;quot;.dialyzer_ignore.exs&amp;quot;
    ]
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach helps you get a passing Dialyzer configuration that you can gradually improve as you fix underlying issues.&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s that!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;As we&amp;#39;ve explored in this deep dive, Dialyzer&amp;#39;s advanced features provide powerful tools for maintaining code quality.
Through proper use of advanced types, you can achieve better encapsulation with opaque types, model complex data structures using recursive types, and create flexible, reusable code with generic types.
These type features form the foundation of robust Elixir applications.&lt;/p&gt;
&lt;p&gt;While there&amp;#39;s a steep learning curve involved in mastering Dialyzer&amp;#39;s advanced features, the investment pays off in more maintainable, better-documented, and more reliable code.
Spending time upfront on proper type specifications and understanding Dialyzer&amp;#39;s intricacies will save you countless hours of debugging and maintenance in the future.&lt;/p&gt;
&lt;p&gt;Happy debugging!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Getting Started with Dialyzer in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/03/18/getting-started-with-dialyzer-in-elixir.html"/>
    <id>https://blog.appsignal.com/2025/03/18/getting-started-with-dialyzer-in-elixir.html</id>
    <published>2025-03-18T00:00:00+00:00</published>
    <updated>2025-03-18T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In part one of this series, we&#039;ll explore the basics of Dialyzer.</summary>
    <content type="html">&lt;p&gt;Dialyzer (DIscrepancy AnaLYZer for ERlang programs) is a powerful static analysis tool that helps developers identify potential issues in their Elixir code without executing it.
It excels at finding type mismatches, unreachable code, and unnecessary functions through sophisticated flow analysis.&lt;/p&gt;
&lt;p&gt;In part one of this two-part series, we&amp;#39;ll first get to grips with the basics of Dialyzer. In part two, we&amp;#39;ll examine more advanced use cases.&lt;/p&gt;
&lt;h2&gt;An Introduction to Dialyzer for Elixir&lt;/h2&gt;
&lt;p&gt;In the world of dynamic languages like Elixir, type-related issues traditionally only surface during runtime, making them harder to catch during development. Dialyzer bridges this gap by analyzing your code&amp;#39;s type specifications and usage patterns to detect potential problems before they reach production.&lt;/p&gt;
&lt;p&gt;When integrated into your development workflow, Dialyzer provides several key benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enhanced Code Reliability&lt;/strong&gt;: Catch type-related bugs early in the development cycle.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better Documentation&lt;/strong&gt;: Type specifications serve as living documentation and provide useful hints with IDE integration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved Developer Productivity&lt;/strong&gt;: Identify issues before they cause runtime errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safer Refactoring&lt;/strong&gt;: Get immediate feedback about type-related changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Setting Up Dialyzer for Elixir&lt;/h2&gt;
&lt;p&gt;While Dialyzer itself comes with Erlang, the recommended way to use it in Elixir projects is through &lt;code&gt;dialyxir&lt;/code&gt;, a mix task that makes Dialyzer more convenient to use.&lt;/p&gt;
&lt;p&gt;First, add &lt;code&gt;dialyxir&lt;/code&gt; to your project&amp;#39;s dependencies in &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def deps do
  [
    {:dialyxir, &amp;quot;~&amp;gt; 1.4&amp;quot;, only: [:dev, :test], runtime: false},
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After adding the dependency, install it by running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can run Dialyzer with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix dialyzer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the first run, Dialyzer will build a Persistent Lookup Table (PLT), which contains information about your project and its dependencies.
This process might take several minutes, but it&amp;#39;s a one-time operation.
The PLT will be cached and reused in subsequent runs.&lt;/p&gt;
&lt;p&gt;The output will look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Compiling PLT .dialyzer_plt
Starting Dialyzer
Total errors: 0, Skipped: 0, Unnecessary Skips: 0
done in 0m1.34s
done (passed successfully)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If Dialyzer finds issues, it will display warnings like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/example.ex:2:invalid_contract
The @spec for the function does not match the success typing of the function.

Function:
Example.hello/0

Success typing:
@spec hello() :: :error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although Dialyzer can infer types from your code, adding explicit type specifications helps it perform a more thorough analysis.
We&amp;#39;ll explore how to write effective type specifications in the next section.&lt;/p&gt;
&lt;h2&gt;Types and Type Specifications in Elixir&lt;/h2&gt;
&lt;p&gt;Type specifications serve multiple purposes in Elixir.
Beyond documentation, they provide Dialyzer with the information needed to perform sophisticated flow analysis. As someone who&amp;#39;s worked extensively with Elixir in production, I&amp;#39;ve found that well-designed type specifications:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Act as executable documentation&lt;/li&gt;
&lt;li&gt;Enable early bug detection&lt;/li&gt;
&lt;li&gt;Make refactoring safer&lt;/li&gt;
&lt;li&gt;Improve IDE integration&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Adding Typespecs to Your Elixir Code&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s start with the basics and progress to more complex scenarios.
There are two main type attributes you&amp;#39;ll use frequently:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;@type name :: &amp;lt;&amp;lt;type scpecification&amp;gt;&amp;gt;&lt;/code&gt; defines a type with the specified name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@spec function_name(argument_types) :: return_type&lt;/code&gt; defines a function specification.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are several &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/typespecs.html#basic-types&quot;&gt;built-in types&lt;/a&gt; like &lt;code&gt;any()&lt;/code&gt;, &lt;code&gt;none()&lt;/code&gt;, &lt;code&gt;atom()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, and &lt;code&gt;integer()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is also possible to compose types using &lt;code&gt;list(type)&lt;/code&gt;, &lt;code&gt;nonempty_list(type)&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;You can use types defined in other modules as well.
It is quite common for data structures to define their types named &lt;code&gt;t&lt;/code&gt;.
In fact, several Elixir data structures already define types that can be used in your custom typespecs, like &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/String.html#t:t/0&quot;&gt;&lt;code&gt;String.t()&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;Range.t()&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Finally, we can use almost any literal as a type that restricts the allowed values to be like the literal.
For example, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;1..10&lt;/code&gt;, &lt;code&gt;{:ok, type}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll cover advanced attributes to create other special types in the second and final part of this series.&lt;/p&gt;
&lt;p&gt;For now, here&amp;#39;s an example of using some typespecs in practice:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule UserAccount do
  @type status :: :active | :inactive | :suspended
  @type role :: :admin | :user

  @spec create_user(String.t(), status(), role()) :: {:ok, map()} | {:error, String.t()}
  def create_user(name, status, role) do
    # Implementation
  end

  @spec is_active?(status()) :: boolean()
  def is_active?(status), do: status == :active
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We define custom types &lt;code&gt;status&lt;/code&gt; and &lt;code&gt;role&lt;/code&gt; using union types&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;create_user&lt;/code&gt; function specification ensures that arguments are of the correct types&lt;/li&gt;
&lt;li&gt;Dialyzer will catch type mismatches, like passing a number instead of a string for a name&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;#39;ll explore more advanced type attributes like &lt;code&gt;@opaque&lt;/code&gt; in the next post.&lt;/p&gt;
&lt;h2&gt;Understanding Common Dialyzer Warnings&lt;/h2&gt;
&lt;p&gt;Now that we have Dialyzer set up and running, let&amp;#39;s explore the most common warnings you&amp;#39;ll encounter and learn how to address them effectively.&lt;/p&gt;
&lt;h3&gt;1. Match Errors&lt;/h3&gt;
&lt;p&gt;Dialyzer detects unused pattern matches by analyzing your types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
  def ok() do
    unmatched(:ok)
  end

  defp unmatched(:ok), do: :ok

  defp unmatched(:error), do: :error
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;The pattern can never match the type.
Pattern:
:error
Type:
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Redundant Guard Clauses&lt;/h3&gt;
&lt;p&gt;This warning shows Dialyzer&amp;#39;s ability to detect impossible conditions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
  def to_string(%{} = a) when is_binary(a) do
    inspect(a)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# lib/example.ex:2:31:guard_fail The guard clause can never succeed.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&amp;#39;re pattern matching on &lt;code&gt;%{}&lt;/code&gt; (a map) but then using an &lt;code&gt;is_binary/1&lt;/code&gt; guard — these conditions can never be true simultaneously since a value cannot be both a map and a binary.
Such contradictions often indicate logical errors in your code&amp;#39;s flow control.
Remove the contradictory guard or fix the pattern matching based on your intended behavior.&lt;/p&gt;
&lt;h3&gt;3. Unmatched Returns&lt;/h3&gt;
&lt;p&gt;This warning is particularly important for maintaining robust error handling:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
  def ok() do
    :rand.uniform(100)
    |&amp;gt; validate()

    :ok
  end

  defp validate(n) when n &amp;lt; 50, do: :ok
  defp validate(n) when n &amp;gt; 50, do: {:error, &amp;quot;too big&amp;quot;}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/example.ex:unmatched_return
The expression produces a value of type:

:ok | {:error, &amp;lt;&amp;lt;_::56&amp;gt;&amp;gt;}

but this value is unmatched.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dialyzer has detected that the function returns a union type (&lt;code&gt;:ok | {:error, binary()}&lt;/code&gt;) that we are ignoring.
In Elixir, it&amp;#39;s a best practice to handle all possible return values, especially errors.&lt;/p&gt;
&lt;p&gt;To fix this, you should:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pattern match on the result and handle both cases, or&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;with&lt;/code&gt; expressions for cleaner error handling, or&lt;/li&gt;
&lt;li&gt;Explicitly discard the result using &lt;code&gt;_ =&lt;/code&gt; if that&amp;#39;s truly intended&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4. No Local Return&lt;/h3&gt;
&lt;p&gt;This indicates that your function never returns normally — it either raises an exception or runs indefinitely:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
  def ok() do
    Enum.each([1, 2, 3], fn _ -&amp;gt; raise &amp;quot;error&amp;quot; end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/example.ex:no_return
The created anonymous function only terminates with explicit exception.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is common in placeholder code, but in production, you should ensure your functions have proper return paths.&lt;/p&gt;
&lt;p&gt;If the function is meant to be raised, specify &lt;code&gt;no_return()&lt;/code&gt; in the typespec:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@spec do_something() :: no_return()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In addition to obvious no-returns, Dialyzer often also raises this as a side-effect of other errors that lead to a guaranteed exception.&lt;/p&gt;
&lt;p&gt;For example, the following code tries to pass &lt;code&gt;age&lt;/code&gt; as a string when it&amp;#39;s declared type is an integer, leading to a Dialyzer &lt;code&gt;no_return&lt;/code&gt; error as a side-effect of the &lt;code&gt;call&lt;/code&gt; error.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule User do
  @type t :: %__MODULE__{name: String.t(), age: integer()}
  defstruct [:name, :age]

  @spec get_age(User.t()) :: integer()
  def get_age(user), do: user.age
end

defmodule Example do
  def do_something() do
    User.get_age(%User{name: &amp;quot;User&amp;quot;, age: &amp;quot;20&amp;quot;})
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;lib/example.ex:10:7:no_return Function do_something/0 has no local return.
lib/example.ex:11:18:call The function call get_age will not succeed.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can sometimes also happen when a library has incorrect typespecs or complex types that Dialyzer has trouble inferring.&lt;/p&gt;
&lt;p&gt;In such cases, it can be desirable to skip Dialyzer warnings.
This can be achieved by using a special &lt;code&gt;@dialyzer&lt;/code&gt; attribute to disable warnings, specifying a tuple with the warning type and the fuction/arity.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Example do
  @dialyzer {:no_return, do_something: 0}

  def do_something() do
    User.get_age(%User{name: &amp;quot;User&amp;quot;, age: &amp;quot;20&amp;quot;})
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s it for this part of our two-part series!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Getting started with Dialyzer might seem daunting at first, but the benefits are worth the initial setup time.
As you&amp;#39;ve seen, it can catch many common issues before they reach production.&lt;/p&gt;
&lt;p&gt;If you already have a large project without Dialyzer, the trick is to start small. First:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add Dialyzer to your development dependencies&lt;/li&gt;
&lt;li&gt;Begin with a single module&lt;/li&gt;
&lt;li&gt;Add type specifications gradually&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our next and final part of this series, we&amp;#39;ll dive deeper into advanced type specifications, explore sophisticated troubleshooting techniques, and learn how to handle complex scenarios that you might encounter as your codebase grows.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll also look at how to effectively configure Dialyzer for larger projects and establish team-wide practices for maintaining type specifications.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Absinthe for Elixir Monitoring with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/03/04/an-introduction-to-absinthe-for-elixir-monitoring-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2025/03/04/an-introduction-to-absinthe-for-elixir-monitoring-with-appsignal.html</id>
    <published>2025-03-04T00:00:00+00:00</published>
    <updated>2025-03-04T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">We’ll explore how to leverage AppSignal’s automatic instrumentation and custom metrics for Absinthe.</summary>
    <content type="html">&lt;p&gt;Absinthe is a popular GraphQL toolkit for building robust APIs in Elixir.
Monitoring such APIs is essential to ensure performance, detect bottlenecks, and handle errors effectively.
AppSignal offers a seamless way to monitor and gain insights into your Absinthe-powered GraphQL APIs, enabling you to keep applications performant and reliable.&lt;/p&gt;
&lt;p&gt;In this post, we’ll explore how to leverage AppSignal’s automatic instrumentation and custom metrics for Absinthe, along with strategies to monitor errors, track subscriptions, and enhance performance through actionable metrics.&lt;/p&gt;
&lt;h2&gt;Automatic Absinthe for Elixir Instrumentation with AppSignal&lt;/h2&gt;
&lt;p&gt;Setting up AppSignal for your Elixir application is straightforward.
You can follow the &lt;a href=&quot;https://docs.appsignal.com/elixir/installation.html&quot;&gt;official setup guide&lt;/a&gt; to install the AppSignal package and configure it with your application key.
Once integrated, &lt;a href=&quot;https://www.appsignal.com/elixir/absinthe-monitoring&quot;&gt;AppSignal automatically instruments your Absinthe GraphQL API&lt;/a&gt;, giving you insights into the execution time and performance of individual queries and mutations.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of how your AppSignal performance report might look, showcasing query performance breakdown:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-02/absinthe-graphql-sample-breakdown.png&quot; alt=&quot;AppSignal GraphQL Sample Breakdown&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The sample breakdown above shows that GraphQL took 45 ms—this duration covers both parsing the query and encoding the results. Ecto took 37 ms, with most of that time spent executing the database query.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s check out the Event Timeline now:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-02/absinthe-graphql-event-timeline.png&quot; alt=&quot;AppSignal GraphQL Event Timeline&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As you can see, this provides a breakdown of all the Ecto queries performed during the resolution of this query.
With this instrumentation, you can identify slow queries, measure throughput, and understand which resolvers might need optimization—all without adding any manual instrumentation.&lt;/p&gt;
&lt;h2&gt;Handling Errors and Exceptions in Absinthe with AppSignal&lt;/h2&gt;
&lt;p&gt;In GraphQL APIs, errors can occur at multiple points: within resolvers, due to validation issues, or from an underlying data source. AppSignal helps capture and report these errors along with contextual information, making debugging efficient.&lt;/p&gt;
&lt;h3&gt;Resolver Exceptions and Validation Errors&lt;/h3&gt;
&lt;p&gt;When an error occurs in a resolver, AppSignal captures it and provides details about the query that caused the issue, the resolver, and the stack trace.&lt;/p&gt;
&lt;p&gt;For example, if a single field on a GraphQL API has an error, it will be reported on the &amp;quot;Errors&amp;quot; page on AppSignal.
Here&amp;#39;s an example of such an error:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-02/absinthe-error.png&quot; alt=&quot;AppSignal Error&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Clicking on &amp;quot;Inspect latest sample&amp;quot; takes you to the full sample details, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A backtrace that can help us pinpoint where the error originated.&lt;/li&gt;
&lt;li&gt;The full GraphQL query and variables (if any), and a lot of other information that can be useful to reproduce that issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-02/absinthe-sample-backtrace-parameters-session.png&quot; alt=&quot;AppSignal Sample Backtrace/Parameters/Session&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Tracking Custom Metrics&lt;/h2&gt;
&lt;p&gt;While automatic instrumentation provides valuable insights into the performance of your Absinthe API, tracking custom metrics can offer even deeper visibility into specific areas of your application.
Custom metrics allow you to define and collect data points unique to your business logic or performance needs.
AppSignal makes it easy to track these metrics in your Absinthe GraphQL API.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Defining Custom Metrics&lt;/h3&gt;
&lt;p&gt;To start tracking custom metrics, you&amp;#39;ll need to define the specific aspects of your API that you want to measure. This could include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resolver Performance:&lt;/strong&gt; Measure how long specific resolvers take to execute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query Complexity:&lt;/strong&gt; Track the number of fields requested in a query or the depth of the query.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Subscription Events:&lt;/strong&gt; Monitor events related to GraphQL subscriptions, such as connection counts and active subscriptions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Implementing Custom Metrics&lt;/h3&gt;
&lt;p&gt;You can implement custom metrics using AppSignal&amp;#39;s built-in APIs. Here’s a simple example, tracking the execution time of a resolver:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Resolvers.PostResolver do
  def get_pots(_, %{id: id}, _) do
    start_time = System.monotonic_time()

    case Blog.get_post(id) do
      nil -&amp;gt;
        Appsignal.increment_counter(&amp;quot;post.not_found&amp;quot;)
        {:error, &amp;quot;Post not found&amp;quot;}

      post -&amp;gt;
        duration = System.monotonic_time() - start_time
        Appsignal.set_gauge(&amp;quot;post.fetch_time&amp;quot;, duration)
        {:ok, post}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you&amp;#39;ve defined and implemented your custom metrics, you can view them in your AppSignal dashboard, which includes various graphs and charts.
These graphs and charts are crucial for identifying trends over time, such as increasing fetch times or spikes in &amp;#39;post not found&amp;#39; errors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-02/absinthe-custom-metrics-dashboard.png&quot; alt=&quot;AppSignal Custom Metrics Dashboard Example&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Monitoring Absinthe Subscriptions&lt;/h3&gt;
&lt;p&gt;Subscriptions in Absinthe allow for real-time updates, typically used in chat or notification systems. Monitoring these subscriptions is crucial to ensure they perform well throughout their lifecycle.&lt;/p&gt;
&lt;h3&gt;Example: Monitoring Subscription Performance&lt;/h3&gt;
&lt;p&gt;A typical Absinthe subscription might look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;subscription :comment_added do
  arg :post_id, non_null(:id)

  config fn args, _ -&amp;gt;
    {:ok, topic: args.post_id}
  end

  trigger :comment_added, topic: fn %{post_id: post_id} -&amp;gt; &amp;quot;post:#{post_id}&amp;quot; end

  resolve fn comment, _, _ -&amp;gt;
    {:ok, comment}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar to custom metrics monitoring, we can track subscription activation time, latency during updates, total active subscriptions at any given time, and any errors that occur within these subscriptions, giving you full visibility into their behavior.&lt;/p&gt;
&lt;p&gt;Here’s how to add basic instrumentation to measure the time required to set up and resolve the subscription.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;field :comment_added, :comment do
  arg(:post_id, non_null(:id))

  config(fn %{post_id: id} = _args, %{context: context} -&amp;gt;
    Appsignal.instrument(&amp;quot;subscription.config&amp;quot;, &amp;quot;Setting up subscription&amp;quot;, fn -&amp;gt;
      {:ok, topic: &amp;quot;post:#{id}&amp;quot;}
    end)
  end)

  resolve(fn comment, _, _ -&amp;gt;
    Appsignal.instrument(&amp;quot;subscription.resolve&amp;quot;, &amp;quot;Resolving subscription&amp;quot;, fn -&amp;gt;
      {:ok, comment}
    end)
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s it for our whistle-stop tour of Absinthe monitoring using AppSignal!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Monitoring GraphQL APIs with AppSignal enables Elixir developers to maintain high performance, quickly diagnose errors, and leverage custom metrics for business-critical operations. Whether you&amp;#39;re tracking query execution, debugging resolver errors, or ensuring efficient subscription handling, AppSignal equips you with the necessary tools to build and maintain robust Absinthe applications.&lt;/p&gt;
&lt;p&gt;If you are building complex APIs with Absinthe, ensure you integrate AppSignal to enhance your observability and performance monitoring. For further reading, explore &lt;a href=&quot;https://docs.appsignal.com/elixir/integrations/absinthe.html&quot;&gt;AppSignal&amp;#39;s Absinthe documentation&lt;/a&gt; and &lt;a href=&quot;https://blog.appsignal.com/2023/05/16/an-introduction-to-absinthe-for-elixir.html&quot;&gt;this four-part series on building scalable GraphQL APIs with Absinthe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building a Distributed Rate Limiter in Elixir with HashRing</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/02/04/building-a-distributed-rate-limiter-in-elixir-with-hashring.html"/>
    <id>https://blog.appsignal.com/2025/02/04/building-a-distributed-rate-limiter-in-elixir-with-hashring.html</id>
    <published>2025-02-04T00:00:00+00:00</published>
    <updated>2025-02-04T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">We&#039;ll build a distributed rate limiter using HashRing for Elixir.</summary>
    <content type="html">&lt;p&gt;Communication between processes in the Erlang VM happens through message passing. In fact,
all communication across processes occurs through the same mechanism. All you need is an address and you can send a
message to it, with the lower level building blocks being &lt;code&gt;send&lt;/code&gt; and &lt;code&gt;receive&lt;/code&gt;. This is true even if that address
is on another node in a cluster of Elixir nodes that are aware of each other. In fact, it works in exactly the same way.&lt;/p&gt;
&lt;p&gt;There’s no special RPC syntax, no special error handling. In fact, you can write your code without knowing whether a
message is destined for another node or process running on the same node. In an example &lt;code&gt;send(address, message)&lt;/code&gt;
the &lt;code&gt;address&lt;/code&gt; could be a local pid, “via tuple”, or a pid from another node. It could be a registered
name combined with a node in a tuple like &lt;code&gt;{node, MyProcess}&lt;/code&gt;. &lt;code&gt;send&lt;/code&gt; will figure out what to do. This is also true
when using the higher level versions &lt;code&gt;GenServer.cast/2&lt;/code&gt; and &lt;code&gt;GenServer.call/3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It might not be obvious at first glance, but this is a superpower. Let’s take a simple example of
some code that runs on a single node and then upgrade it to share state across a cluster of nodes. To
follow along, all you’ll need is Elixir installed.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=7yU9mvwZKoY&quot;&gt;This blog post is an extended version of an example from my Code BEAM Mexico keynote&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;A Basic In-Memory Rate Limiter&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule RateLimiter do
  def check(ip) do
    Hammer.check_rate(ip, 60_000, 10)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my example, I’m wrapping the &lt;a href=&quot;https://github.com/ExHammer/hammer&quot;&gt;Hammer&lt;/a&gt; rate limiting library, although you could
use any other library or roll your own. With our &lt;code&gt;RateLimiter&lt;/code&gt; module we can now lock down the endpoints in our
imaginary web app and protect our service. We’re very strict, only allowing 10 requests per minute per IP.&lt;/p&gt;
&lt;p&gt;But as
we scale up and add more nodes, this basic rate limiting module doesn’t work anymore because it’s not sharing
state across the nodes. The same IP is now able to make more than 10 requests per minute, as the requests are randomly
assigned to different nodes by the load balancer.&lt;/p&gt;
&lt;p&gt;There are, of course, tons of ways of solving this problem. Hammer itself comes with an adapter for Redis that allows
sharing state across multiple nodes. Don&amp;#39;t get me wrong — Redis is a great piece of software, but you might not need it. Maybe there’s a way to solve this, using Elixir and nothing else.&lt;/p&gt;
&lt;h2&gt;Interlude: Connecting Nodes&lt;/h2&gt;
&lt;p&gt;To try this out on your own machine, you’ll need to connect two Elixir nodes together. To get started, assuming you’ve
got Elixir installed locally, you’ll want to start &lt;code&gt;iex&lt;/code&gt; but with a special flag:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex --name a@127.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, in a second terminal/tab:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex --name b@127.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, in either terminal, type in &lt;code&gt;Node.list&lt;/code&gt; and verify that it’s an empty list, and then
&lt;code&gt;Node.ping(:”x@127.0.0.1”)&lt;/code&gt; replacing &lt;code&gt;x&lt;/code&gt; with the name of the other node — the one you&amp;#39;re not currently using. You
should see a &lt;code&gt;:pong&lt;/code&gt; response. Now try typing in &lt;code&gt;Node.list&lt;/code&gt; again and verify that it shows the other node in the
list. That’s it, you’ve made your first cluster!&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Note that if you get a &lt;code&gt;:pang&lt;/code&gt;, you may need to run the command &lt;code&gt;epmd&lt;/code&gt; in your terminal first, to start the service
that connects the nodes.&lt;/p&gt;
&lt;h2&gt;Hash Rings&lt;/h2&gt;
&lt;p&gt;The first tool we’ll need is a mechanism for associating keys with nodes in a cluster. I’m a big fan of &lt;a href=&quot;https://github.com/discord/ex_hash_ring&quot;&gt;Discord’s HashRing library&lt;/a&gt; so we’ll use that, but there are alternative
implementations out there. This is based on an ingenious idea from the ‘90s around returning consistent look-up
results given the same outputs. Basically, we can add all of our node names to the ring, and when we look up keys we
can rely on getting the same result every time (assuming the node names in the ring are the same). Even when they
change, we should see minimal changes in our look-ups:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(b@127.0.0.1)4&amp;gt; alias ExHashRing.Ring
ExHashRing.Ring
iex(b@127.0.0.1)5&amp;gt; {:ok, ring} = Ring.start_link()
{:ok, #PID&amp;lt;0.279.0&amp;gt;}

# The keys you add to the ring can be anything, but for our purposes
# we&amp;#39;re interested in node names.
iex(b@127.0.0.1)6&amp;gt; Ring.add_node(ring, &amp;quot;a@127.0.0.1&amp;quot;)
{:ok, [{&amp;quot;a@127.0.0.1&amp;quot;, 512}]}
iex(b@127.0.0.1)7&amp;gt; Ring.add_node(ring, &amp;quot;b@127.0.0.1&amp;quot;)
{:ok, [{&amp;quot;b@127.0.0.1&amp;quot;, 512}, {&amp;quot;a@127.0.0.1&amp;quot;, 512}]}
iex(b@127.0.0.1)16&amp;gt; Ring.add_node(ring, &amp;quot;c@127.0.0.1&amp;quot;)
{:ok, [{&amp;quot;c@127.0.0.1&amp;quot;, 512}, {&amp;quot;b@127.0.0.1&amp;quot;, 512}, {&amp;quot;a@127.0.0.1&amp;quot;, 512}]}

# Now that they&amp;#39;re in there, we can take it for a spin. Let&amp;#39;s try checking
# some different look ups.
iex(b@127.0.0.1)18&amp;gt; Ring.find_node(ring, &amp;quot;result1&amp;quot;)
{:ok, &amp;quot;c@127.0.0.1&amp;quot;}
iex(b@127.0.0.1)19&amp;gt; Ring.find_node(ring, &amp;quot;result2&amp;quot;)
{:ok, &amp;quot;a@127.0.0.1&amp;quot;}
iex(b@127.0.0.1)21&amp;gt; Ring.find_node(ring, &amp;quot;result4&amp;quot;)
{:ok, &amp;quot;b@127.0.0.1&amp;quot;}

# Okay, but what if we remove a node?
iex(b@127.0.0.1)22&amp;gt; Ring.remove_node(ring,&amp;quot;c@127.0.0.1&amp;quot;)
{:ok, [{&amp;quot;b@127.0.0.1&amp;quot;, 512}, {&amp;quot;a@127.0.0.1&amp;quot;, 512}]}
iex(b@127.0.0.1)23&amp;gt; Ring.find_node(ring, &amp;quot;result4&amp;quot;)
{:ok, &amp;quot;b@127.0.0.1&amp;quot;}
iex(b@127.0.0.1)24&amp;gt; Ring.find_node(ring, &amp;quot;result1&amp;quot;)
{:ok, &amp;quot;a@127.0.0.1&amp;quot;}

# As you can see, result4 still results in node b even though the
# memberships changed, and result1 has been moved over to a.
# But what if we add the node c back?
iex(b@127.0.0.1)25&amp;gt; Ring.add_node(ring, &amp;quot;c@127.0.0.1&amp;quot;)
{:ok, [{&amp;quot;c@127.0.0.1&amp;quot;, 512}, {&amp;quot;b@127.0.0.1&amp;quot;, 512}, {&amp;quot;a@127.0.0.1&amp;quot;, 512}]}
iex(b@127.0.0.1)26&amp;gt; Ring.find_node(ring, &amp;quot;result1&amp;quot;)
{:ok, &amp;quot;c@127.0.0.1&amp;quot;}
# result1 is now back on c. It will always go to c, those are the
# behaviors we can rely on from the hash ring.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay! Now let’s hook into OTP to grab all the node names and add them to the ring, and additionally, use some events
to keep the ring up to date as nodes connect and disconnect. You can use this code alongside manually connecting
and disconnecting nodes from the terminal like I demonstrated above. However, in a production environment, you may want to use a library like &lt;a href=&quot;https://github.com/bitwalker/libcluster&quot;&gt;libcluster&lt;/a&gt; to manage your cluster more efficiently.&lt;/p&gt;
&lt;p&gt;First of all, add a HashRing to your &lt;code&gt;application.ex&lt;/code&gt; like this &lt;code&gt;{ExHashRing.Ring, name: DistributionRing}&lt;/code&gt;. Then add
the following module to your app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Distribution do
  use GenServer

  require Logger

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  @impl GenServer
  def init(_opts) do
    :net_kernel.monitor_nodes(true)

    for node &amp;lt;- [Node.self() | Node.list()] do
      ExHashRing.Ring.add_node(DistributionRing, node)
    end

    {:ok, []}
  end

  @impl GenServer
  def handle_info({:nodeup, node}, state) do
    Logger.info(&amp;quot;Node #{node} connected&amp;quot;)
    ExHashRing.Ring.add_node(DistributionRing, node)
    {:noreply, state}
  end

  def handle_info({:nodedown, node}, state) do
    Logger.info(&amp;quot;Node #{node} disconnected&amp;quot;)
    ExHashRing.Ring.remove_node(DistributionRing, node)
    {:noreply, state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a GenServer responsible for maintaining that hash ring, adding and removing nodes as they connect and
disconnect. Go ahead and try it out right now if you want. You should see
the log messages show up as you add and remove nodes with &lt;code&gt;Node.ping&lt;/code&gt;. Pretty neat.&lt;/p&gt;
&lt;p&gt;Now we have everything we need to upgrade our simple rate limiting module to share data across the cluster.&lt;/p&gt;
&lt;h2&gt;Distributed Rate Limiter&lt;/h2&gt;
&lt;p&gt;Let’s do this in two steps. First, we need to turn our basic rate limiting module into a GenServer so that there’s a
process on each node that can be reached from the other nodes. We’re doing it in two steps to really hammer home the
difference between the version that only works locally and the version that returns consistent results across the
cluster.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule RateLimiter do
  use GenServer

  # Public interface
  def check(ip) do
    check_internal(ip)
  end

  def start_link(_opts) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init(_opts) do
    {:ok, []}
  end

  # Internal implementation
  def handle_call({:check, ip}, _from, state) do
    {:reply, check_internal(ip), state}
  end

  defp check_internal(ip) do
    Hammer.check_rate(ip, 60_000, 10)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure you add that process to your application children, like &lt;code&gt;{RateLimiter, []}&lt;/code&gt;. Then let’s upgrade:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule RateLimiter do
  use GenServer

  require Logger

  # Public interface
  def check(ip) do
    {:ok, node} = ExHashRing.Ring.find_node(DistributionRing, ip)
    GenServer.call({__MODULE__, node}, {:check, ip})
  catch
    :exit, reason -&amp;gt;
      Logger.warning(&amp;quot;Tried to check rate limit but failed&amp;quot;, reason: inspect(reason))

      # As a fallback, do a local check. It&amp;#39;s better than nothing!
      check_internal(ip)
  end

  def start_link(_opts) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init(_opts) do
    {:ok, []}
  end

  # Internal implementation
  def handle_call({:check, ip}, _from, state) do
    {:reply, check_internal(ip), state}
  end

  defp check_internal(ip) do
    Hammer.check_rate(ip, 60_000, 10)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re taking a laissez-faire approach to error handling here overall. This code is just something to get you started,
but I do think it’s worth having that &lt;code&gt;catch&lt;/code&gt; in the &lt;code&gt;check&lt;/code&gt; function. When &lt;code&gt;GenServer.call/3&lt;/code&gt; fails it exits and
crashes the caller, this would, for example, happen where it’s not able to reach the process on the other node. Because
networks are not reliable, this will happen. Fortunately, short interval rate limiting is a use case that doesn’t
demand absolutely perfect results. We can very easily fall back to just checking locally instead, and at worst, a few extra requests may need to be made. As long as the network is mostly stable, we’ll be fine.&lt;/p&gt;
&lt;p&gt;So there it is. With those two magical lines, looking up the node and then passing the node to &lt;code&gt;GenServer.call/3&lt;/code&gt;, we took
code that ran fully locally, to code that now transparently routes requests to the proper nodes in the cluster. Given
a specific IP address, the lookup will always happen on the node that is responsible for that IP address, and even if
nodes are going up or down it is &lt;em&gt;likely&lt;/em&gt; to be handled by the same node anyway!&lt;/p&gt;
&lt;h2&gt;A Word of Warning&lt;/h2&gt;
&lt;p&gt;I do want to emphasize that this isn’t necessarily the “right” tool for every use case. In my opinion, it works well
for short-lived rate limiting because it’s ok if we’re a little bit wrong sometimes. It’s also ok that we lose state
on app restarts. The rate limit quotas reset every minute anyway!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;If you’re concerned about routing these rate limit lookups through GenServers, remember that they can easily handle
tens of thousands of messages per second. And if you need more than that, you’ll probably need to look at something
more robust than this! But for the majority of apps that need multiple nodes, maybe for resiliency and nothing else,
this can be a great alternative to Redis or other solutions, helping you keep your stack lean and not worry
about maintaining extra services.&lt;/p&gt;
&lt;p&gt;To summarize: you get the semantics of just calling code locally, transparent routing across your
cluster, and you don’t even need to add another service to maintain. And remember, with 3 nodes, every 3 lookups on
average will happen locally, amortizing your overall network latency overhead!&lt;/p&gt;
&lt;p&gt;You don’t need to limit yourself to
rate limiting either, there are tons of use cases where you can apply this pattern. Why not add some simple ephemeral
caches? Or how about some high cardinality metrics/event reporting? Your options are limitless, so why not bring a
little bit of distributed Elixir &lt;em&gt;magic&lt;/em&gt; into your app.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Tracking Errors in Tesla with AppSignal for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2025/01/21/tracking-errors-in-tesla-with-appsignal-for-elixir.html"/>
    <id>https://blog.appsignal.com/2025/01/21/tracking-errors-in-tesla-with-appsignal-for-elixir.html</id>
    <published>2025-01-21T00:00:00+00:00</published>
    <updated>2025-01-21T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s track and handle Tesla errors in your Elixir app using AppSignal.</summary>
    <content type="html">&lt;p&gt;While Elixir provides built-in libraries (like HTTPoison) for making HTTP requests, the Tesla library has gained popularity due to its simplicity, ease of use, and extensibility. Tesla offers a clean and composable way to define requests, handle responses, and customize client behavior.&lt;/p&gt;
&lt;p&gt;Even so, whenever you&amp;#39;re working with external APIs, errors are inevitable. Network issues, server downtime, rate limiting, and unexpected responses can all lead to errors in your application. As such, it’s great to have a dependable error tracking mechanism in place to quickly identify, diagnose, and resolve issues.&lt;/p&gt;
&lt;p&gt;AppSignal is a powerful application monitoring and error tracking solution that seamlessly integrates with Elixir apps and libraries such as Tesla.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll explore how to effectively track and handle Tesla errors in your app using AppSignal. We&amp;#39;ll start by understanding the basics of Tesla and its key features. Then we&amp;#39;ll set up a simple weather forecasting application that integrates Tesla with AppSignal. Along the way, we&amp;#39;ll discuss common error scenarios, implement error handling techniques, and showcase how to leverage AppSignal&amp;#39;s intuitive dashboard to monitor and analyze errors.&lt;/p&gt;
&lt;h2&gt;Pre-requisites&lt;/h2&gt;
&lt;p&gt;First, ensure you have the following in place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An AppSignal account. Don&amp;#39;t have one? &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;Sign up for a free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://weatherapi.com&quot;&gt;WeatherAPI account&lt;/a&gt; to fetch weather data.&lt;/li&gt;
&lt;li&gt;Some experience working with Elixir and the Phoenix framework.&lt;/li&gt;
&lt;li&gt;An Elixir/Phoenix application to work with. You can &lt;a href=&quot;https://github.com/iamaestimo/weather_forecast_app&quot;&gt;fork the weather forecast app&lt;/a&gt; which we&amp;#39;ll use throughout this tutorial.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And with that, let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Brief Overview of Tesla for Elixir&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hex.pm/packages/tesla&quot;&gt;Tesla&lt;/a&gt; is a modular Elixir HTTP client library that you can use to build HTTP clients with flexible middleware configurations. This middleware configuration allows you to extend the behavior of your HTTP client, with features such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt; - With Tesla, you can configure basic or token-based authentication schemes, or even define your own custom scheme.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error handling&lt;/strong&gt; - You can configure the middleware to intercept request errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching and rate limits&lt;/strong&gt; - You can set up custom caching rules and API call rate limits to reduce the number of API calls your client makes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Introducing Our Weather App Built with Phoenix&lt;/h2&gt;
&lt;p&gt;The application we&amp;#39;ll use to demonstrate Tesla&amp;#39;s features is a simple weather forecasting app built with Phoenix. It will feature a home page with a form input where a user can enter the name of a city. Upon the form submission, the user is redirected to another page that will display a three-day weather forecast. The weather forecast data will be fetched from the &lt;a href=&quot;https://weatherapi.com&quot;&gt;Weather API&lt;/a&gt; service using a Tesla HTTP client.&lt;/p&gt;
&lt;p&gt;Although we won&amp;#39;t go through a step-by-step walk-through of building the weather forecast Phoenix app, I will highlight some of the app&amp;#39;s key features, especially how Tesla fits in and where some potential issues could come from.&lt;/p&gt;
&lt;p&gt;Below is the summarized shell output of the &lt;code&gt;tree&lt;/code&gt; command on the &lt;code&gt;lib&lt;/code&gt; directory, which contains the most important parts of the app for our discussion:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;-&amp;gt; lib
├── weather_forecast
│   ├── ...
│   └── weather_api.ex
├── weather_forecast.ex
├── weather_forecast_web
│   ├── components
│   │   ├── ...
│   ├── controllers
│   │   ├── ...
│   │   ├── weather_controller.ex
│   │   ├── weather_html
│   │   │   ├── forecast.html.heex
│   │   │   └── index.html.heex
│   │   └── weather_html.ex
│   ├── ...
└── weather_forecast_web.ex
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API client&lt;/strong&gt; - The API client found in the &lt;code&gt;lib/weather_forecast/weather_api.ex&lt;/code&gt; file uses Tesla to make and parse HTTP requests from the &lt;em&gt;weatherapi.com&lt;/em&gt; API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weather controller&lt;/strong&gt; - Contains two actions, &lt;code&gt;index&lt;/code&gt; and &lt;code&gt;forecast&lt;/code&gt;. The &lt;code&gt;index&lt;/code&gt; action renders a form input for entering a city name. The &lt;code&gt;forecast&lt;/code&gt; action takes the city parameter and calls the API client to fetch the weather forecast, which responds with the weather forecast data or an error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The views&lt;/strong&gt; - The index view displays the form input where a user will enter a city name and be redirected to the forecast view upon form submission. There, a three-day weather forecast or an error will be displayed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over the coming sections, we&amp;#39;ll use this app to instrument Tesla API requests, errors, and more. For now, let&amp;#39;s see how we can add AppSignal and Tesla to the app.&lt;/p&gt;
&lt;h2&gt;Adding AppSignal and Tesla to the Weather App&lt;/h2&gt;
&lt;p&gt;Open up the &lt;code&gt;mix.exs&lt;/code&gt; file and add the lines shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
...
    defp deps do
        [
            {:tesla, &amp;quot;~&amp;gt; 1.12&amp;quot;},
            {:hackney, &amp;quot;~&amp;gt; 1.20&amp;quot;},
            {:appsignal, &amp;quot;~&amp;gt; 2.8&amp;quot;}
        ]
    end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might be wondering what Hackney is and how it fits in here. While Tesla is a great choice for wrapping HTTP requests intuitively, an adapter is still needed to handle the actual job of opening connections, sending requests, parsing responses, and so forth, which is what Hackney does. That said, Hackney isn&amp;#39;t the only adapter; &lt;a href=&quot;https://hexdocs.pm/tesla/readme.html#adapters&quot;&gt;there are other adapters like Finch and Gun that you can use&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With that out of the way, run &lt;code&gt;mix deps.get&lt;/code&gt; to fetch the packages, then &lt;code&gt;mix appsignal.install &amp;lt;YOUR APPSIGNAL API KEY&amp;gt;&lt;/code&gt; to run the AppSignal interactive package installer, which will ask you to choose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The name of your application&lt;/li&gt;
&lt;li&gt;The configuration method (an environment variable or a configuration file).&lt;/li&gt;
&lt;/ul&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;You&amp;#39;ll get an output similar to the one shown below if the process runs without a hitch.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Validating Push API key: Valid! 🎉
What is your application&amp;#39;s name? [weather_app]: weather_tesla_app

There are two methods of configuring AppSignal in your application.
  Option 1: Using a &amp;quot;config/appsignal.exs&amp;quot; file. (1)
  Option 2: Using system environment variables.  (2)

What is your preferred configuration method? [1]: 1
Writing config file config/appsignal.exs: Success!
Linking config to config/config.exs: Success!
Activating dev environment: Success!
Activating prod environment: Success!
...
AppSignal installed! 🎉
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once done, you should have AppSignal installed, and your app will start sending data to the AppSignal dashboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-01/initial-appsignal-dashboard.png&quot; alt=&quot;Initial AppSignal dashboard&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Configuring Tesla&lt;/h2&gt;
&lt;p&gt;However, we need to add a few configurations to Tesla and Hackney to complete the installation.&lt;/p&gt;
&lt;p&gt;To begin with, add the &lt;code&gt;Tesla.Middleware.Telemetry&lt;/code&gt; which plugs into the app&amp;#39;s built-in telemetry. This needs to be the first middleware in the API client, as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/weather_forecast/weather_api.ex

defmodule WeatherForecast.WeatherApi do
  use Tesla

  plug Tesla.Middleware.Telemetry  # This line should be first
  # ..then the rest of the middleware follow

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But before we continue, it&amp;#39;s important to highlight how this use of middleware makes Tesla unique among Elixir HTTP clients.&lt;/p&gt;
&lt;h3&gt;The Concept of “Composable Middleware” in Tesla&lt;/h3&gt;
&lt;p&gt;Tesla uses the concept of &amp;quot;composable middleware&amp;quot; similar to the &lt;em&gt;Plug router&lt;/em&gt;, which means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With Tesla, you can define a middleware chain where each middleware is executed in the order it appears for each HTTP request. For example, the &lt;code&gt;Tesla.Middleware.Telemetry&lt;/code&gt; middleware is first in the chain in the API client and, as such, will be executed first.&lt;/li&gt;
&lt;li&gt;It&amp;#39;s heavily inspired by &lt;code&gt;Plug&lt;/code&gt;, which makes it easy to use different middleware as you wish.&lt;/li&gt;
&lt;li&gt;You have access to several built-in middleware, such as the JSON middleware, the Logger middleware, and others. At the same time, you can define your own custom middleware to implement custom logic on requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;#39;s crucial to execute the &lt;code&gt;Tesla.Middleware.Telemetry&lt;/code&gt; middleware first, to ensure that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It records the start of an event before another middleware processes that event.&lt;/li&gt;
&lt;li&gt;It captures an event as it is before another middleware processes that event.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s now complete the configuration by adding the Hackney configuration to &lt;code&gt;dev.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...

config :tesla, adapter: Tesla.Adapter.Hackney
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With everything configured, fire up the app and test it out a bit. You should start to see request data on your AppSignal dashboard, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-01/initial-tesla-requests.png&quot; alt=&quot;Initial Tesla requests&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Everything looks great so far! Let&amp;#39;s now use AppSignal&amp;#39;s powerful custom instrumentation features to get more information on Tesla&amp;#39;s requests.&lt;/p&gt;
&lt;h2&gt;Instrumenting Tesla with AppSignal&lt;/h2&gt;
&lt;p&gt;With the custom instrumentation provided by AppSignal, we can add informational tags to Tesla&amp;#39;s requests to give us more insight into what is actually going on under the hood.&lt;/p&gt;
&lt;p&gt;Modify the API client&amp;#39;s &lt;code&gt;get_forecast/1&lt;/code&gt; function as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/weather_forecast/weather_api.ex

defmodule WeatherForecast.WeatherApi do
  use Tesla

  plug Tesla.Middleware.Telemetry
  ...

  def get_forecast(city) do
    Appsignal.instrument(&amp;quot;Weather API - Get Forecast&amp;quot;, &amp;quot;WeatherAPI Forecast for #{city}&amp;quot;, fn -&amp;gt;
      client()
      |&amp;gt; get(&amp;quot;/forecast.json&amp;quot;, query: [q: city, days: 3])
      |&amp;gt; case do
        {:ok, %{status: 200, body: body}} -&amp;gt; {:ok, parse_forecast(body)}
        {:ok, %{status: status, body: body}} -&amp;gt;
          IO.inspect(body, label: &amp;quot;API error response&amp;quot;)
          {:error, &amp;quot;API request failed with status #{status}&amp;quot;}
        {:error, error} -&amp;gt; {:error, error}
      end
    end)
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;code&gt;AppSignal.instrument/2-3&lt;/code&gt; function wraps the code where we define it in a span. In the case of the weather forecast app, this is the &lt;code&gt;get_forecast/1&lt;/code&gt; function. When this code is executed, the span captures useful information such as execution time and any errors that might occur.&lt;/p&gt;
&lt;p&gt;The screenshots below show how such instrumented requests are captured on the AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-01/tesla-custom-instrumentation-1.png&quot; alt=&quot;Tesla custom instrumentation - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And if you click on the link shown, you get even more information on the request:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-01/tesla-custom-instrumentation-2.png&quot; alt=&quot;Tesla custom instrumentation - 2&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Tesla Errors&lt;/h2&gt;
&lt;p&gt;Whenever you work with an HTTP client library like Tesla, you can expect some of the errors listed below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rate-limiting errors&lt;/li&gt;
&lt;li&gt;Authentication errors&lt;/li&gt;
&lt;li&gt;Network errors&lt;/li&gt;
&lt;li&gt;Response errors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And more.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s pick one of these and show how to custom instrument it using AppSignal.&lt;/p&gt;
&lt;h2&gt;Instrumenting Tesla Authentication Errors with AppSignal&lt;/h2&gt;
&lt;p&gt;Different APIs will require different authentication mechanisms. For the &lt;em&gt;WeatherAPI.com&lt;/em&gt; API, authentication is accomplished through an API key.&lt;/p&gt;
&lt;p&gt;To simulate an authentication error, I&amp;#39;m going to regenerate the API key, but still use the old API key with the weather forecast app. Then I&amp;#39;ll modify the API client&amp;#39;s &lt;code&gt;get_forecast/1&lt;/code&gt; function, as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WeatherForecast.WeatherApi do
  ...

    def get_forecast(city) do
        Appsignal.instrument(&amp;quot;Weather API - Get Forecast&amp;quot;, fn span -&amp;gt;
        Appsignal.Span.set_sample_data(span, &amp;quot;params&amp;quot;, %{city: city})

        client()
        |&amp;gt; get(&amp;quot;/forecast.json&amp;quot;, query: [q: city, days: 3])
        |&amp;gt; case do
            {:ok, %{status: 200, body: body}} -&amp;gt;
            {:ok, parse_forecast(body)}
            {:ok, %{status: status, body: body}} -&amp;gt;
            error_message = &amp;quot;API request failed with status #{status}&amp;quot;
            stacktrace = get_application_stacktrace()
            Appsignal.send_error(%RuntimeError{message: error_message},
                                stacktrace,
                                fn error_span -&amp;gt;
                                    Appsignal.Span.set_sample_data(error_span, &amp;quot;error&amp;quot;, %{
                                    status: status,
                                    body: body,
                                    city: city
                                    })
                                end)
            {:error, error_message}
            {:error, %Tesla.Error{reason: reason} = error} -&amp;gt;
            error_message = &amp;quot;API request failed: #{inspect(reason)}&amp;quot;
            stacktrace = get_application_stacktrace()
            Appsignal.send_error(error,
                                stacktrace,
                                fn error_span -&amp;gt;
                                    Appsignal.Span.set_sample_data(error_span, &amp;quot;error&amp;quot;, %{
                                    reason: reason,
                                    city: city
                                    })
                                end)
            {:error, error_message}
        end
        end)
    end

    defp get_application_stacktrace do
        {_, full_stacktrace} = Process.info(self(), :current_stacktrace)
            Enum.filter(full_stacktrace, fn {module, _function, _arity, _location} -&amp;gt;
                to_string(module) =~ &amp;quot;WeatherForecast&amp;quot;
        end)
    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s a breakdown of what&amp;#39;s going on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We first wrap the &lt;code&gt;get_forecast/1&lt;/code&gt; function with &lt;code&gt;AppSignal.instrument/2&lt;/code&gt;, then define a new span using &lt;code&gt;AppSignal.Span.set_sample_data/3&lt;/code&gt;, with the city name as the sample data.&lt;/li&gt;
&lt;li&gt;A request is then made to the weather forecast API. If an error occurs (in this case, the authentication error that we expect), the error is created with all the information we need and then forwarded to the app&amp;#39;s AppSignal dashboard.&lt;/li&gt;
&lt;li&gt;The private &lt;code&gt;get_application_stacktrace&lt;/code&gt; function gets the full stack trace of the current process. Since this can include a bunch of entries from other Phoenix/Elixir modules, we filter for those that contain the string &amp;quot;WeatherForecast&amp;quot; as this is what we are really interested in. This filtered stack trace is what gets sent to AppSignal.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the dashboard results below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-01/runtime-error.png&quot; alt=&quot;Runtime error in errors list&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As well as the error details:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-01/runtime-error-details.png&quot; alt=&quot;Runtime error details&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And, finally, the stack trace sample:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2025-01/runtime-error-details-with-backtrace.png&quot; alt=&quot;Stacktrace sample&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s that!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we explored how the Elixir HTTP client library Tesla works.&lt;/p&gt;
&lt;p&gt;We learned how to install and use Tesla in a Phoenix application and then installed AppSignal to instrument Tesla requests. We custom-instrumented requests to dig deeper into stack traces and the time taken for API calls. With this information, you are now better equipped to build more effective performance profiling for your Elixir apps.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>AppSignal’s Top 5 Elixir Posts in 2024</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/12/17/appsignals-top-5-elixir-posts-in-2024.html"/>
    <id>https://blog.appsignal.com/2024/12/17/appsignals-top-5-elixir-posts-in-2024.html</id>
    <published>2024-12-17T00:00:00+00:00</published>
    <updated>2024-12-17T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">It&#039;s time for our yearly rundown of our top 5 best-performing Elixir posts.</summary>
    <content type="html">&lt;p&gt;As 2024 comes to a close, we’re thrilled to highlight our top five Elixir articles that captured the most attention this year!&lt;/p&gt;
&lt;h2&gt;Top 5 Elixir Blog Posts in 2024 ⚗️&lt;/h2&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/01/23/build-a-simple-tracing-system-in-elixir.html&quot;&gt;Build A Simple Tracing System in Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this post, we added tracing to an Elixir application using OpenTelemetry and streamlined the process.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/10/29/managing-distributed-state-with-genservers-in-phoenix-and-elixir.html&quot;&gt;Managing Distributed State with GenServers in Phoenix and Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This two-part series explored working with Phoenix in a distributed setup. Part one looked at GenServers.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/03/05/powerful-caching-in-elixir-with-cachex.html&quot;&gt;Powerful Caching in Elixir with Cachex&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Improve the performance of your Elixir application with Cachex, a powerful caching library.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/05/21/using-dependency-injection-in-elixir.html&quot;&gt;Using Dependency Injection in Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dependency injection can prove useful in Elixir. In this first part of a two-part series, we looked at some basic concepts, core principles, and types of dependency injection.&lt;/p&gt;
&lt;p&gt;Finally, here&amp;#39;s our most viewed Elixir post in 2024!&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2024/07/23/enhancing-your-elixir-codebase-with-gleam.html&quot;&gt;Enhancing Your Elixir Codebase with Gleam&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We looked at the benefits of using Gleam and then added Gleam code to an Elixir project.&lt;/p&gt;
&lt;h2&gt;Season&amp;#39;s Greetings ❆ ⛄&lt;/h2&gt;
&lt;p&gt;Have a wonderful festive break, and we&amp;#39;ll see you in the new year!&lt;/p&gt;
&lt;p&gt;If you haven’t already, don’t forget to &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter&lt;/a&gt;, so you never miss an upcoming post.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Distributed Phoenix: Deployment and Scaling</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/12/10/distributed-phoenix-deployment-and-scaling.html"/>
    <id>https://blog.appsignal.com/2024/12/10/distributed-phoenix-deployment-and-scaling.html</id>
    <published>2024-12-10T00:00:00+00:00</published>
    <updated>2024-12-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In part one of this series, we managed distributed state using GenServers. In this part, we&#039;ll explore deployment and scaling strategies.</summary>
    <content type="html">&lt;p&gt;In part one of this series, we managed distributed state using GenServers. This provided a foundation for understanding some core concepts in distributed Phoenix applications.&lt;/p&gt;
&lt;p&gt;Now, we turn our focus to deployment and scaling strategies.
As your application evolves to meet growing demands, knowing how to scale horizontally, maintain high availability, and monitor distributed components becomes crucial.&lt;/p&gt;
&lt;p&gt;This post will walk you through best practices for deploying and scaling Phoenix applications in a distributed setup, ensuring they are performant and resilient.&lt;/p&gt;
&lt;h2&gt;Distributed Deployment Strategies&lt;/h2&gt;
&lt;p&gt;Deploying a Phoenix application in a distributed environment introduces some unique challenges and opportunities that are less common to traditional web stacks.
Thanks to the underlying power of the BEAM VM, Elixir applications offer native clustering capabilities.&lt;/p&gt;
&lt;p&gt;When deployed correctly, a distributed Phoenix app becomes more than a collection of stateless servers — it turns into a unified system where instances can communicate directly, share state, and respond gracefully to network failures.&lt;/p&gt;
&lt;p&gt;Let’s explore two common deployment strategies for Phoenix apps: single-node and multi-node deployment.&lt;/p&gt;
&lt;h3&gt;Single-Node Deployment&lt;/h3&gt;
&lt;p&gt;In smaller setups, it’s possible to run your Phoenix app as a single instance.
You can package the app either as a &lt;a href=&quot;https://hexdocs.pm/phoenix/releases.html&quot;&gt;mix release&lt;/a&gt; (recommended for all deployments, as it packages the app into a single directory that includes everything you need to run the app), or simply run it with &lt;a href=&quot;https://hexdocs.pm/phoenix/deployment.html#starting-your-server-in-production&quot;&gt;mix phx.server&lt;/a&gt; with the correct environment variables.&lt;/p&gt;
&lt;p&gt;This is common for small-scale deployments where high availability isn’t critical and the load can be handled by a single server.
The pros are that it&amp;#39;s a simple deployment with minimal overhead and is easy to manage.
But your web server is also now a single point of failure.
Though unsuitable for large-scale distributed systems, single-node deployments are a good starting point before introducing more complexity.&lt;/p&gt;
&lt;h3&gt;Deployment Across Multiple Nodes&lt;/h3&gt;
&lt;p&gt;A node in the context of a Phoenix (or Elixir) application refers to a single instance of the BEAM VM, capable of running the Phoenix app and connecting with other nodes to form a cluster.&lt;/p&gt;
&lt;p&gt;Each node can share its state and manage processes independently, but can also interact with other nodes when deployed together.&lt;/p&gt;
&lt;p&gt;To deploy a Phoenix application across multiple nodes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Multiple Instances&lt;/strong&gt;:
Use tools like Docker, Kubernetes, or your preferred cloud provider (like AWS EC2 or DigitalOcean Droplets) to create multiple instances of your Phoenix application.
Each instance will act as an independent node.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set Up Clustering&lt;/strong&gt;:
Configure the nodes to communicate with each other by setting the &lt;code&gt;RELEASE_DISTRIBUTION&lt;/code&gt; and &lt;code&gt;RELEASE_NODE&lt;/code&gt; environment variables.
For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;RELEASE_DISTRIBUTION=name
RELEASE_NODE=app_name@host
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each node should be configured with a unique name (like &lt;code&gt;app_name@host1&lt;/code&gt;, &lt;code&gt;app_name@host2&lt;/code&gt;, etc.), allowing them to recognize each other within the cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Load Balancing&lt;/strong&gt;: Place a load balancer in front of nodes to distribute incoming requests evenly.
On AWS, for example, you can use an Elastic Load Balancer (ELB) and configure it to forward requests to nodes.
In the load balancer setup, specify the DNS or IP of each node and configure health checks to detect if any node goes down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Testing the Cluster&lt;/strong&gt;: Once the nodes are up, test that they recognize each other.
You can use &lt;code&gt;:observer.start()&lt;/code&gt; (or connect via &lt;code&gt;iex&lt;/code&gt; shell) to inspect the network status of nodes and verify they’re communicating as expected.
This can be done by running and checking the return value.
The command will return &lt;code&gt;:pong&lt;/code&gt; if the node is reachable and &lt;code&gt;:pang&lt;/code&gt; otherwise.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;iex&amp;gt; Node.ping(:&amp;quot;app_name@host2&amp;quot;)
:pong
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With clustering, Phoenix applications can benefit from shared state and inter-node communication.
Scenarios like real-time messaging, shared PubSub broadcasts, and distributed task management (e.g., using Horde) are enabled in a clustered setup.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Native support for process distribution across nodes.&lt;/li&gt;
&lt;li&gt;Enables the use of libraries like Horde for distributed task management.&lt;/li&gt;
&lt;li&gt;Stateful GenServers and ETS tables can be shared or replicated between nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Requires attention to network partitions (nodes becoming temporarily unreachable).&lt;/li&gt;
&lt;li&gt;Inter-node communication adds complexity — issues like split-brain scenarios must be handled.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Scaling a Distributed Phoenix Application&lt;/h2&gt;
&lt;p&gt;Horizontal scaling is often the go-to strategy for distributed applications.
An external user&amp;#39;s first point of contact with your app is usually the web layer.
Scaling this layer is easy — add more instances of your Phoenix app behind a load balancer to handle increased traffic.
To further distribute load, use CDNs to offload static asset delivery.&lt;/p&gt;
&lt;p&gt;Before adding more web servers, scaling processes allows an application to handle more load within a single instance by distributing work across lightweight processes.
The most common way to achieve this is using background job processing.
Using libraries like &lt;a href=&quot;https://hexdocs.pm/oban/Oban.html&quot;&gt;Oban&lt;/a&gt;, an application can spawn lightweight processes to handle background tasks.
These processes are isolated and managed independently by the BEAM scheduler, improving concurrency without increasing web layer load.&lt;/p&gt;
&lt;p&gt;Finally, for apps that significantly scale, your database needs to keep up with new connections from the scaled-up web and background job processes.
The easiest way to scale a database is through vertical scaling — keep adding more CPU power and memory to the database server.&lt;/p&gt;
&lt;p&gt;An alternative to this is to have read replicas to distribute read-heavy workloads from the primary database server.&lt;/p&gt;
&lt;p&gt;Your setup on the database side will depend a lot on the database (Postgres, MySQL, etc.) and the cloud provider.
On the app side, &lt;a href=&quot;https://hexdocs.pm/ecto/replicas-and-dynamic-repositories.html&quot;&gt;Ecto can be configured with multiple repositories to leverage replicas for reading queries&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Considerations for High Availability&lt;/h2&gt;
&lt;p&gt;High Availability (HA) ensures that your application remains operational even in the face of failure, minimizing downtime and disruptions.
Phoenix applications, powered by the BEAM VM, are particularly well-suited for building HA systems due to native support for fault tolerance, process isolation, and clustering.&lt;/p&gt;
&lt;p&gt;Let’s explore strategies for ensuring high availability in Phoenix apps, along with specific tools and techniques tailored for Elixir-based architectures.&lt;/p&gt;
&lt;h3&gt;Clustering and Node Redundancy&lt;/h3&gt;
&lt;p&gt;A core feature of the BEAM ecosystem is clustering, where multiple nodes work together to act as a single, logical system.&lt;/p&gt;
&lt;p&gt;In a Phoenix app, clustering ensures that instances (nodes) share state and responsibilities dynamically.
When clustered, nodes can pass messages between processes on different instances, ensuring tasks or state can failover seamlessly if a node goes down.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html&quot;&gt;Phoenix.PubSub&lt;/a&gt; benefits from clustering, enabling nodes to broadcast real-time updates (like notifications) across the cluster without additional complexity.&lt;/p&gt;
&lt;h3&gt;Load Balancing and Failover&lt;/h3&gt;
&lt;p&gt;Load balancing ensures that traffic is evenly distributed across all available nodes, while failover mechanisms detect unhealthy nodes and redirect requests to healthy instances.
Use NGINX or HAProxy to route HTTP traffic between multiple Phoenix nodes.
If using WebSockets, enable sticky sessions to maintain persistent connections between users and the same server.
In a Kubernetes environment, use Service objects or Ingress controllers to manage traffic between pod instances.&lt;/p&gt;
&lt;p&gt;Set health checks to monitor node availability, removing unresponsive nodes from the load balancer pool.&lt;/p&gt;
&lt;p&gt;Use Erlang’s node monitoring features to detect when nodes leave or join the cluster and adjust load distribution accordingly.&lt;/p&gt;
&lt;h3&gt;Fault Tolerance with Process Isolation&lt;/h3&gt;
&lt;p&gt;The BEAM VM’s design philosophy revolves around process isolation, meaning that failure in one part of the system does not bring down the entire app. This makes it easier to build systems that gracefully recover from failures.&lt;/p&gt;
&lt;p&gt;Every Phoenix app is backed by supervision trees, where supervisors restart crashed processes automatically.
In complex apps (e.g., background job workers or live dashboards), GenServers can isolate logic into independent processes that recover individually when something goes wrong.&lt;/p&gt;
&lt;h3&gt;Zero-Downtime Deployments&lt;/h3&gt;
&lt;p&gt;In highly available systems, every deployment needs to occur without any downtime, especially when serving global users around the clock.&lt;/p&gt;
&lt;p&gt;Here are a few strategies for zero-downtime deployments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blue-Green Deployments&lt;/strong&gt;: Run two identical environments (blue and green) and switch traffic between them seamlessly after the deployment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rolling Deployments&lt;/strong&gt;: Update nodes incrementally, keeping some instances online while others are upgraded.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hot Code Upgrades&lt;/strong&gt;: &lt;a href=&quot;https://blog.appsignal.com/2021/07/27/a-guide-to-hot-code-reloading-in-elixir.html&quot;&gt;With Distillery or Releases, you can deploy changes without restarting your application&lt;/a&gt; (though this requires some additional planning).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Monitoring and Maintenance&lt;/h2&gt;
&lt;p&gt;No distributed system is truly complete without robust monitoring and proactive maintenance.
Ensuring high performance and quick resolution of issues requires tracking key metrics, receiving alerts on failures, and understanding application behavior in real time.&lt;/p&gt;
&lt;p&gt;Phoenix applications, with their modular design and reliance on the BEAM VM, offer a wealth of telemetry options.&lt;/p&gt;
&lt;p&gt;This section explores monitoring techniques and best practices for keeping a distributed Phoenix app healthy and resilient over time.&lt;/p&gt;
&lt;h3&gt;Phoenix for Elixir Application Monitoring with Telemetry and Tracing&lt;/h3&gt;
&lt;p&gt;Monitoring starts with gaining visibility into the core operations of your application.
Phoenix provides out-of-the-box support for Telemetry, enabling developers to track key metrics such as response times, database query performance, and request rates.&lt;/p&gt;
&lt;p&gt;Phoenix emits Telemetry events for things like HTTP requests, database interactions, and process life cycles.
These metrics allow you to pinpoint performance bottlenecks and detect abnormal behavior.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;Tools like AppSignal&lt;/a&gt; seamlessly integrate with Phoenix and Ecto, providing dashboards for tracking application performance, error rates, and system health.&lt;/p&gt;
&lt;h3&gt;Error Tracking and Alerts&lt;/h3&gt;
&lt;p&gt;Even with the best architecture, errors are inevitable in production.
A good error-tracking system ensures that you are alerted to issues as soon as they occur, allowing for quick resolution and minimal impact on users.&lt;/p&gt;
&lt;p&gt;AppSignal captures errors, including crashes, unhandled exceptions, database timeouts, and more! Here&amp;#39;s an example of how an Ecto error looks in AppSignal:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-11/ecto-no-result-error.png&quot; alt=&quot;Ecto error&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can also &lt;a href=&quot;https://www.appsignal.com/tour/errors&quot;&gt;configure alerts&lt;/a&gt; based on error frequency or severity to be notified about critical issues in real time.&lt;/p&gt;
&lt;p&gt;This can be really useful. For example, a surge of 500 Internal Server Error responses can indicate an overloaded node or an unexpected database issue.&lt;/p&gt;
&lt;h3&gt;Tracking Metrics Across Nodes&lt;/h3&gt;
&lt;p&gt;Distributed Phoenix applications require centralized monitoring to aggregate data from all nodes.
Without this, diagnosing issues across multiple instances becomes difficult.
Some key node metrics to track include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node Uptime&lt;/strong&gt;: Track how long each node has been online and watch for frequent restarts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory and Process Utilization&lt;/strong&gt;: Monitor the number of BEAM processes and memory consumption on each node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PubSub Metrics&lt;/strong&gt;: Track the number of connected WebSocket clients and broadcast messages across the cluster.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we explored key strategies for deploying and scaling distributed Phoenix applications.
We’ve covered the essential practices needed for building resilient, scalable systems.
With monitoring tools and proactive maintenance, you can ensure your app is ready to meet future demands.&lt;/p&gt;
&lt;p&gt;Together, parts one and two provide a comprehensive guide to developing, deploying, and maintaining distributed Phoenix applications.&lt;/p&gt;
&lt;p&gt;Mastering these techniques will empower you to deliver robust systems capable of handling real-world challenges.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Track Errors in Oban for Elixir Using AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/11/12/how-to-track-errors-in-oban-for-elixir-using-appsignal.html"/>
    <id>https://blog.appsignal.com/2024/11/12/how-to-track-errors-in-oban-for-elixir-using-appsignal.html</id>
    <published>2024-11-12T00:00:00+00:00</published>
    <updated>2024-11-12T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s learn what Oban is, how it works, and how to instrument it using AppSignal.</summary>
    <content type="html">&lt;p&gt;When developing an Elixir app, you&amp;#39;ll often need to handle tasks in a way that does not interrupt the normal user request-response cycle.&lt;/p&gt;
&lt;p&gt;Tasks like sending emails are great examples of jobs that should be delegated to a capable background job processing service. In the Elixir ecosystem, Oban is one such background job processing library.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll learn what Oban is, how it works, and how to instrument it using AppSignal.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, I recommend you have the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An AppSignal account - &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;you can sign up for a free trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;An Elixir app. In my case, I am using a Phoenix LiveView app with a landing page where a user can subscribe to an email newsletter with a couple of background jobs to schedule and send out emails. You can go ahead and &lt;a href=&quot;https://github.com/iamaestimo/phoenix_liveview_email_subscription_app&quot;&gt;fork the app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://docs.appsignal.com/elixir/installation.html&quot;&gt;AppSignal package added and configured for your app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Elixir, Phoenix, and PostgreSQL installed on your local development environment.&lt;/li&gt;
&lt;li&gt;Some basic experience of working with Elixir and Phoenix.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And with that, we can get started.&lt;/p&gt;
&lt;h2&gt;Introducing Oban&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sorentwo/oban&quot;&gt;Oban&lt;/a&gt; is a stable and high-performing background job processing library for Elixir applications. Unlike other job processing systems that might require their own infrastructure to run background jobs, such as RabbitMQ and Sidekiq (which needs a key-value store like Redis), Oban uses your app&amp;#39;s existing PostgreSQL or SQLite database.&lt;/p&gt;
&lt;p&gt;With Oban, you can define, enqueue, and process jobs in the background. Another important thing to note is that Oban jobs are persistent, which means that even if something unexpected happens in the server environment, jobs will be retried for you.&lt;/p&gt;
&lt;h2&gt;Installing and Configuring Oban in Elixir&lt;/h2&gt;
&lt;p&gt;First, add Oban to your app&amp;#39;s &lt;code&gt;mix.exs&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs

defmodule EmailSubscriptionApp.MixProject do
  ...

  defp deps do
    [
      ...
      {:oban, &amp;quot;~&amp;gt; 2.17&amp;quot;}
    ]
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run &lt;code&gt;mix deps.get&lt;/code&gt; in the terminal to install the package and its dependencies.&lt;/p&gt;
&lt;p&gt;Before moving on, it&amp;#39;s important to cover the database your app is using since it will determine how you configure Oban.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;ve already configured PostgreSQL for your app, the Postgres package is likely already installed, and you&amp;#39;ll not have to add it manually. However, if your app uses SQLite, you&amp;#39;ll have to add the &lt;a href=&quot;https://hex.pm/packages/ecto_sqlite3&quot;&gt;EctoSQLite3&lt;/a&gt; package to &lt;code&gt;mix.exs&lt;/code&gt; and configure it accordingly. In this article, the featured app uses PostgreSQL for the database, and Oban is installed to run on top of that.&lt;/p&gt;
&lt;p&gt;Next, generate a migration file that will create all the database tables Oban needs to run and keep tabs on job queues.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix ecto.gen.migration add_oban_jobs_table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then modify the generated file to look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# priv/repo/migrations/timestamp_add_oban_jobs_table.exs

defmodule EmailSubscriptionApp.Repo.Migrations.AddObanJobsTable do
  use Ecto.Migration

  def up do
    Oban.Migration.up(version: 12)
  end

  def down do
    Oban.Migration.down(version: 1)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the migration with &lt;code&gt;mix ecto.migrate&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;With that done, you next need to configure Oban to run with the Postgres engine by adding the following lines to &lt;code&gt;config.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/config.exs

config :email_subscription_app, Oban,
  engine: Oban.Engines.Basic,
  queues: [default: 10],
  repo: EmailSubscriptionApp.Repo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s also recommended that you prevent Oban from running jobs in testing mode by adding the lines below to &lt;code&gt;text.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/text.exs

config :email_subscription_app, Oban, testing: :inline
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we&amp;#39;ll need to add Oban to the app&amp;#39;s list of supervised children since they run as isolated supervision trees. To do this, add Oban to the app supervisor like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailSubscriptionApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      ...
      EmailSubscriptionApp.Repo,
      {Oban, Application.fetch_env!(:email_subscription_app, Oban)},
      ...
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, to finish up the installation and configuration, open up a new interactive Elixir shell with &lt;code&gt;iex -S mix&lt;/code&gt;. Run the command &lt;code&gt;Oban.config()&lt;/code&gt; to return an output similar to the one below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Oban.config()
%Oban.Config{
  dispatch_cooldown: 5,
  engine: Oban.Engines.Basic,
  get_dynamic_repo: nil,
  insert_trigger: true,
  log: false,
  name: Oban,
  node: &amp;quot;...&amp;quot;,
  notifier: {Oban.Notifiers.Postgres, []},
  peer: {Oban.Peers.Postgres, []},
  plugins: [],
  prefix: &amp;quot;public&amp;quot;,
  queues: [default: [limit: 10]],
  repo: EmailSubscriptionApp.Repo,
  shutdown_grace_period: 15000,
  stage_interval: 1000,
  testing: :disabled
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before moving on to defining a few jobs and instrumenting them using AppSignal, let&amp;#39;s touch on how instrumentation actually works.&lt;/p&gt;
&lt;h2&gt;Automatic Instrumentation of Oban Using AppSignal&lt;/h2&gt;
&lt;p&gt;When you added the AppSignal package to your app, Oban instrumentation was automatically added. The AppSignal package provides instrumentation for Oban workers and will also collect metrics on how background jobs are performing.&lt;/p&gt;
&lt;p&gt;With that in mind, let&amp;#39;s write a few jobs and see how they appear on the AppSignal dashboard.&lt;/p&gt;
&lt;h2&gt;Defining the First Background Job&lt;/h2&gt;
&lt;p&gt;Our practice Phoenix application is all about receiving a user&amp;#39;s email in an input on the homepage, then sending that user a series of emails (starting with a welcome email that is sent immediately when the user subscribes, a follow-up email sent ten minutes later, and then a final email sent thirty minutes later).&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start by defining the background job that will trigger the first email.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/email_subscription_app/workers/welcome_email_worker.ex

defmodule EmailSubscriptionApp.Workers.WelcomeEmailWorker do
  use Oban.Worker, queue: :default

  alias EmailSubscriptionApp.Emails.{EmailSender, Mailer}

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{&amp;quot;email&amp;quot; =&amp;gt; email}}) do
    email
    |&amp;gt; EmailSender.welcome_email()
    |&amp;gt; Mailer.deliver()

    :ok
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s dig into this example code a bit to understand how Oban workers work. This information will prove helpful when troubleshooting job errors.&lt;/p&gt;
&lt;p&gt;You have the module definition — in this case, the &lt;code&gt;WelcomeEmailWorker&lt;/code&gt; — then one or more job-performing functions, usually called &lt;code&gt;perform/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;perform/1&lt;/code&gt; function receives an &lt;code&gt;Oban.Job&lt;/code&gt; struct containing the specific job&amp;#39;s arguments which, in our case, is the &lt;code&gt;email&lt;/code&gt; key.&lt;/p&gt;
&lt;p&gt;Even though we haven&amp;#39;t shown it in this example code, Oban also allows for job scheduling using the &lt;code&gt;schedule_at&lt;/code&gt; and &lt;code&gt;schedule_in&lt;/code&gt; options.&lt;/p&gt;
&lt;p&gt;And like we mentioned before, AppSignal automatically instruments Oban and displays some default dashboards, as you can see in the examples below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-11/automatic-instrumentation-oban.png&quot; alt=&quot;Automatic instrumentation of Oban on AppSignal&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Here are our Oban workers listed on AppSignal:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-11/oban-workers-list.png&quot; alt=&quot;Oban workers listed on AppSignal&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And details of a worker&amp;#39;s instrumentation:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-11/worker-instrumentation-details.png&quot; alt=&quot;Worker instrumentation&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;ve installed Oban, defined a simple background worker job, instrumented Oban with AppSignal, and visualized the output. Let&amp;#39;s turn to when things go wrong with Oban and how we can use AppSignal to help us track errors.&lt;/p&gt;
&lt;h2&gt;Oban Errors&lt;/h2&gt;
&lt;p&gt;Although Elixir systems are well-known for their fault tolerance, errors and bugs can affect them, resulting in a poor user experience if not addressed. In this section, we&amp;#39;ll look at some common errors that could affect your Oban workers, as well as how you can instrument errors with AppSignal and see them on your dashboard.&lt;/p&gt;
&lt;p&gt;Many different errors could affect an Oban worker, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Database connection errors&lt;/strong&gt; - Since Oban depends on accessing a PostgreSQL or SQLite 3 database, any connection issues between your app and its database will definitely affect any workers you have defined.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;External service failures&lt;/strong&gt; - For example, if there is an issue that affects emails being sent through a third-party email service provider in an email subscription app, the background jobs we&amp;#39;ve defined could fail to send emails, which would result in Oban job errors. Further, if you call third-party API services from your app, any rate-limiting efforts by the API service provider could result in connected Oban jobs failing to complete and resulting in errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Job timeout errors&lt;/strong&gt; - These errors occur if a job&amp;#39;s actual execution time exceeds the configured time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Job queue congestion errors&lt;/strong&gt; - These happen when there are too many jobs in the queue, which could result in delays in job execution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Instrumenting Oban Errors Using AppSignal for Elixir&lt;/h2&gt;
&lt;p&gt;One of the major benefits of AppSignal is that most common errors are automatically instrumented for you. For example, see the code snippet below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailSubscriptionApp.Workers.WelcomeEmailWorker do
  use Oban.Worker, queue: :default
  alias EmailSubscriptionApp.Emails.{EmailSender, Mailer}

  @impl Oban.Worker
  def perform(%Oban.Job{args: %{&amp;quot;email&amp;quot; =&amp;gt; email}}) do
    email
    |&amp;gt; EmailSender.welcome_email()
    |&amp;gt; Mailer.deliver()
    |&amp;gt; case do
      {:ok, _} -&amp;gt; :ok
      {:error, reason} -&amp;gt;
        raise &amp;quot;Mailer delivery error: #{inspect(reason)}&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If an error occurs within the &lt;code&gt;perform/1&lt;/code&gt; function, AppSignal will catch it and give you a dashboard view with details of the error, as you can see in the screenshot below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-11/error-instrumentation.png&quot; alt=&quot;Error instrumentation&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Before wrapping up this article, let&amp;#39;s take a look at the error details AppSignal shows you in the dashboard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Error message&lt;/strong&gt; - The actual error message associated with the raised error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backtrace&lt;/strong&gt; - The backtrace gives you fine-grained context on what happens before an error occurs in your app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameters&lt;/strong&gt; - AppSignal also shows you any parameters involved when the error occurred.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy&lt;/strong&gt; - Finally, you also get information on whether the error occurred during a deployment or not.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that&amp;#39;s that!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we looked at the background job processing package Oban. We learned how to install it, configure background workers, simulate an error, and instrument errors using AppSignal. I recommend using this information as a foundation for using Oban and AppSignal in your Elixir apps.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Managing Distributed State with GenServers in Phoenix and Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/10/29/managing-distributed-state-with-genservers-in-phoenix-and-elixir.html"/>
    <id>https://blog.appsignal.com/2024/10/29/managing-distributed-state-with-genservers-in-phoenix-and-elixir.html</id>
    <published>2024-10-29T00:00:00+00:00</published>
    <updated>2024-10-29T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">This two-part series explores working with Phoenix in a distributed setup. In part one, we&#039;ll look at GenServers.</summary>
    <content type="html">&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&amp;#39;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 &amp;quot;token bucket&amp;quot; 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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.TokenBucketRateLimiter do
  use GenServer

  # tokens per second
  @rate 1
  # maximum tokens in the bucket
  @bucket_size 10

  def start_link([]), do: GenServer.start_link(__MODULE__, nil, name: __MODULE__)

  @impl true
  def init(nil), do: {:ok, %{buckets: %{}}}

  def allow?(client_id) do
    GenServer.call(__MODULE__, {:allow?, client_id})
  end

  @impl true
  def handle_call({:allow?, client_id}, _from, state) do
    current_time = System.monotonic_time(:second)
    {reply, updated_bucket} =
      state.buckets
      |&amp;gt; get_or_init_bucket(client_id)
      |&amp;gt; update_bucket(current_time)
      |&amp;gt; maybe_consume_token(current_time)

    state = put_in(state, [:buckets, client_id], updated_bucket)
    {:reply, reply, state}
  end

  defp maybe_consume_token(%{tokens: tokens} = bucket, current_time)
       when tokens &amp;gt;= 1 do
    updated_bucket = %{bucket | tokens: tokens - 1, last_checked: current_time}
    {true, updated_bucket}
  end

  defp maybe_consume_token(bucket, _current_time), do: {false, bucket}

  defp get_or_init_bucket(buckets, client_id) do
    Map.get(buckets, client_id, %{
      tokens: @bucket_size,
      last_checked: current_time
    })
  end

  defp update_bucket(bucket, current_time) do
    # Add tokens based on the last time the bucket was checked
    time_passed = current_time - bucket.last_checked
    new_tokens = time_passed * @rate
    updated_tokens = min(bucket.tokens + new_tokens, @bucket_size)
    %{bucket | tokens: updated_tokens, last_checked: current_time}
  end
end
&lt;/code&gt;&lt;/pre&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&amp;#39;s supervision tree to start the API rate limiter automatically:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Other Children...
      MyApp.TokenBucketRateLimiter
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; 1..11 |&amp;gt; Enum.map(fn _i -&amp;gt; MyApp.TokenBucketRateLimiter.allow?(&amp;quot;some client id&amp;quot;) end)
[true, true, true, true, true, true, true, true, true, true, false]

iex&amp;gt; Process.sleep(1000)
:ok
iex&amp;gt; MyApp.TokenBucketRateLimiter.allow?(&amp;quot;some client id&amp;quot;)
true
&lt;/code&gt;&lt;/pre&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&amp;#39;s state is just a single integer for the token size and a single integer for the timestamp, this doesn&amp;#39;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;Banner lang=&quot;elixir&quot; /&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&amp;#39;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.
This is simple to do using Erlang&amp;#39;s &lt;a href=&quot;https://www.erlang.org/docs/18/man/global&quot;&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=&quot;https://hexdocs.pm/elixir/GenServer.html#module-name-registration&quot;&gt;&lt;code&gt;GenServer.start_link/3&lt;/code&gt;&lt;/a&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.
Let&amp;#39;s update the code to do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.TokenBucketRateLimiter do
  def start_link([]) do
    GenServer.start_link(__MODULE__, nil, name: {:global, __MODULE__})
  end

  def allow?(client_id) do
    GenServer.call({:global, __MODULE__}, {:allow?, client_id})
  end
end
&lt;/code&gt;&lt;/pre&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&amp;#39;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;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;➜ iex --name node1@127.0.0.1 --cookie asdf -S mix
iex(node1@127.0.0.1)1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;But as soon as we start a second node and connect it to the cluster, the application crashes:&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;➜ iex --name node2@127.0.0.1 --cookie asdf -S mix
iex(node2@127.0.0.1)1&amp;gt; Node.connect(:&amp;quot;node1@127.0.0.1&amp;quot;)
[notice] Application my_app exited: shutdown
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def start_link([]) do
  tuple = {:global, __MODULE__}

  case GenServer.whereis(tuple) do
    nil -&amp;gt; GenServer.start_link(__MODULE__, nil, name: tuple)
    _pid -&amp;gt; :ignore
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that&amp;#39;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&amp;#39;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=&quot;https://github.com/derekkraan/delta_crdt_ex&quot;&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=&quot;https://github.com/derekkraan/horde&quot;&gt;&lt;code&gt;Horde&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/bitwalker/swarm&quot;&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&amp;#39;s add it to &lt;code&gt;mix.exs&lt;/code&gt; to get started:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.MixProject do
  defp deps do
    [
      # ...
      {:delta_crdt, &amp;quot;~&amp;gt; 0.6.3&amp;quot;}
    ]
  end
end
&lt;/code&gt;&lt;/pre&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=&quot;https://hexdocs.pm/delta_crdt/DeltaCrdt.AWLWWMap.html&quot;&gt;&lt;code&gt;AWLWWMap&lt;/code&gt;&lt;/a&gt; (that stands for &amp;#39;Add-Wins Last-Write-Wins Map) so that in the case of a conflict, the last write always wins.
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=&quot;https://hexdocs.pm/delta_crdt/DeltaCrdt.html#set_neighbours/2&quot;&gt;&lt;code&gt;set_neighbours/2&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:ok, crdt1} = DeltaCrdt.start_link(DeltaCrdt.AWLWWMap)
{:ok, crdt2} = DeltaCrdt.start_link(DeltaCrdt.AWLWWMap)
DeltaCrdt.set_neighbours(crdt1, [crdt2])
DeltaCrdt.read(crdt1)
%{}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once neighbours are set, adding any data to one CRDT automatically syncs with the second one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;DeltaCrdt.put(crdt1, &amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;)
DeltaCrdt.read(crdt2)
%{&amp;quot;foo&amp;quot; =&amp;gt; &amp;quot;bar&amp;quot;}
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.TokenBucketRateLimiter do
  use GenServer

  def start_link([]), do: GenServer.start_link(__MODULE__, nil, name: global_tuple())

  defp global_tuple(node \\ Node.self()), do: {:global, to_string(node) &amp;lt;&amp;gt; to_string(__MODULE__)}
end
&lt;/code&gt;&lt;/pre&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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.TokenBucketRateLimiter do
  use GenServer

  @impl true
  def init(nil) do
    {:ok, crdt} = DeltaCrdt.start_link(DeltaCrdt.AWLWWMap, sync_interval: 100)

    {:ok, %{crdt: crdt}}
  end

  def allow?(client_id), do: GenServer.call(global_tuple(), {:allow?, client_id})

  @impl true
  def handle_call({:allow?, client_id}, _from, state) do
    current_time = System.os_time(:second)

    {reply, updated_bucket} =
      state.crdt
      |&amp;gt; get_or_init_bucket(client_id, current_time)
      |&amp;gt; update_bucket(current_time)
      |&amp;gt; maybe_consume_token(current_time)

    # Update the CRDT with the new bucket state
    DeltaCrdt.put(state.crdt, client_id, updated_bucket)

    {:reply, reply, state}
  end

  defp get_or_init_bucket(crdt, client_id, current_time) do
    case DeltaCrdt.get(crdt, client_id) do
      nil -&amp;gt; default_bucket(current_time)
      bucket -&amp;gt; bucket
    end
  end

  defp default_bucket(time), do: %{tokens: @bucket_size, last_checked: time}
end
&lt;/code&gt;&lt;/pre&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&amp;#39;s create a new function named &lt;code&gt;update_neighbours&lt;/code&gt; inside the GenServer that does this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp update_neighbours(crdt) do
  neighbours =
    Node.list()
    |&amp;gt; Enum.map(fn node -&amp;gt;
      node
      |&amp;gt; global_tuple()
      |&amp;gt; GenServer.whereis()
      |&amp;gt; :sys.get_state()
      |&amp;gt; Map.get(:crdt)
    end)

  DeltaCrdt.set_neighbours(crdt, neighbours)
end
&lt;/code&gt;&lt;/pre&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.
Let&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp refresh_peer_neighbours() do
  Node.list()
  |&amp;gt; Enum.each(fn node -&amp;gt;
    node
    |&amp;gt; global_tuple()
    |&amp;gt; GenServer.whereis()
    |&amp;gt; Process.send(pid, :refresh_neighbours, [])
  end)
end

@impl true
def handle_info(:refresh_neighbours, state) do
  update_neighbours(state.crdt)
  {:noreply, state}
end
&lt;/code&gt;&lt;/pre&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=&quot;https://www.erlang.org/doc/apps/kernel/net_kernel.html#monitor_nodes-1&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@impl true
def init(nil) do
  {:ok, crdt} = DeltaCrdt.start_link(DeltaCrdt.AWLWWMap, sync_interval: 100)

  # Monitor for addition of new nodes
  :net_kernel.monitor_nodes(true)

  {:ok, %{crdt: crdt}, {:continue, nil}}
end

@impl true
def handle_info({:nodeup, _node}, state) do
  Process.send_after(self(), :refresh_neighbours, 1_000)
  {:noreply, state}
end

def handle_info({:nodedown, _node}, state) do
  Process.send_after(self(), :refresh_neighbours, 1_000)
  {:noreply, state}
end
&lt;/code&gt;&lt;/pre&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=&quot;https://gist.github.com/pulkit110/6497bd0b8e1ff78d87253bd3cb66ecb9&quot;&gt;Here is the full implementation&lt;/a&gt;.
Let&amp;#39;s take it for a spin:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Node 1
➜ iex --name node1@127.0.0.1 --cookie asdf -S mix
iex(node1@127.0.0.1)1&amp;gt;

# Node2
➜ iex --name node2@127.0.0.1 --cookie asdf -S mix
iex(node2@127.0.0.1)1&amp;gt; Node.connect(:&amp;quot;node1@127.0.0.1&amp;quot;)
true
iex(node2@127.0.0.1)2&amp;gt; MyApp.TokenBucketRateLimiter.allow?(&amp;quot;some client id&amp;quot;)
true
iex(node2@127.0.0.1)3&amp;gt; MyApp.TokenBucketRateLimiter.crdt() |&amp;gt; DeltaCrdt.get(&amp;quot;some client id&amp;quot;)
%{tokens: 9, last_checked: 1725358705}

# Back on Node1
iex(node1@127.0.0.1)1&amp;gt; MyApp.TokenBucketRateLimiter.crdt() |&amp;gt; DeltaCrdt.get(&amp;quot;some client id&amp;quot;)
%{tokens: 9, last_checked: 1725358705}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;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&amp;#39;ve taken an in-depth look at how GenServers and Delta CRDTs can be leveraged to manage distributed state in a Phoenix application.
We&amp;#39;ve implemented a token bucket rate limiter across multiple nodes, ensuring consistency and fault tolerance even in a distributed setup.
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&amp;#39;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&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Find and Fix N+1 Queries Using AppSignal for a Phoenix App in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/10/08/find-and-fix-n-plus-1-queries-using-appsignal-for-a-phoenix-app-in-elixir.html"/>
    <id>https://blog.appsignal.com/2024/10/08/find-and-fix-n-plus-1-queries-using-appsignal-for-a-phoenix-app-in-elixir.html</id>
    <published>2024-10-08T00:00:00+00:00</published>
    <updated>2024-10-08T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">We&#039;ll dive into how N+1 queries happen, their impact on performance, and some strategies to detect and fix them with AppSignal.</summary>
    <content type="html">&lt;p&gt;N+1 queries are a frequent issue in complex applications built with Elixir and Phoenix.
These queries can silently degrade application performance, often going unnoticed until they&amp;#39;ve compounded into a significant problem.&lt;/p&gt;
&lt;p&gt;They can substantially increase web page load times, as each additional query adds overhead to a database, consuming more time and resources.
That&amp;#39;s why it&amp;#39;s crucial to detect and resolve N+1 queries to optimize production systems.
It&amp;#39;s not just about maintaining a seamless user experience; it&amp;#39;s also about ensuring you maintain your Elixir application&amp;#39;s scalability and efficiency.&lt;/p&gt;
&lt;p&gt;Using AppSignal, you can identify N+1 queries in Phoenix applications, alongside a comprehensive suite of tools to monitor, diagnose, and rectify performance bottlenecks in Elixir projects.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s explore how N+1 queries happen, their impact on performance, and some strategies to detect and fix them in your Elixir application.&lt;/p&gt;
&lt;h2&gt;Understanding And Fixing N+1 Queries in Phoenix for Elixir&lt;/h2&gt;
&lt;p&gt;N+1 queries occur when an application retrieves a single database record, followed by an additional query for each related record.
In Phoenix applications, N+1 queries often emerge in the context of complex relationships and Ecto associations.&lt;/p&gt;
&lt;p&gt;Even small mistakes in Ecto queries can lead to cascading N+1 issues, resulting in multiple round trips to a database, each fetching only a small amount of data.&lt;/p&gt;
&lt;p&gt;Some common examples include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using &lt;code&gt;Repo.all&lt;/code&gt; without a proper &lt;code&gt;preload&lt;/code&gt; clause (this will not fetch associated records in the same query).&lt;/li&gt;
&lt;li&gt;In GraphQL, when using Absinthe with Elixir, N+1 query issues can arise when resolving fields that require data from associated records.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;em&gt;Check out &lt;a href=&quot;https://blog.appsignal.com/2023/06/06/absinthe-for-large-elixir-applications.html#avoiding-n1-queries-in-elixir&quot;&gt;Avoiding N+1 Queries for Absinthe&lt;/a&gt; for an overview of this topic.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;A Simple Example Using Ecto&lt;/h3&gt;
&lt;p&gt;For instance, consider a blog application where each post has many comments.
A naive Ecto query might retrieve all posts and then run a separate query for each post&amp;#39;s comments.
This results in one query for the posts (&lt;code&gt;N&lt;/code&gt;) and one query for each post&amp;#39;s comments (&lt;code&gt;+1&lt;/code&gt;), which is highly inefficient.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Fetching posts without preloading comments
posts = Repo.all(Post)

# This will cause N+1 queries, as for each post, comments are fetched separately
posts |&amp;gt; Enum.each(fn post -&amp;gt;
  comments = Repo.all(from c in Comment, where: c.post_id == ^post.id)
  IO.inspect(comments)
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above might sound like a contrived example — experienced developers are quite unlikely to do this.
But it is meant to serve as a simplified scenario of how N+1 queries can creep into systems: any query inside a loop is a suspect.
N+1 queries are usually hidden in plain sight, for example, behind a context function like &lt;code&gt;Blog.list_comments(post_id: post.id)&lt;/code&gt; inside the loop.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s discuss a complex scenario.&lt;/p&gt;
&lt;h3&gt;Complex Situations Leading to N+1 Queries&lt;/h3&gt;
&lt;p&gt;Imagine a blog application displaying a feed of all recent posts and the count of comments (or likes) for each post.&lt;/p&gt;
&lt;p&gt;A sample implementation could look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Load posts from subscribed authors
posts = Repo.all(Post)

# Load comments count per post
for post &amp;lt;- posts do
  comments_count = Repo.one(from c in Comment, where: c.post_id == ^post.id, select: count(c.id))
  render(&amp;quot;post.html&amp;quot;, post: post, comments_count: comments_count)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Here, the &lt;code&gt;comments_count&lt;/code&gt; query causes an N+1 problem because we fetch each individual post&amp;#39;s count.
One might argue that we can just add &lt;code&gt;comments&lt;/code&gt; to the preloads and be done with it.
While that solves the N+1 query, it loads too much unnecessary data (we don&amp;#39;t need all the comments yet, only the total number of comments) and might actually hurt loading times.&lt;/p&gt;
&lt;p&gt;A better solution is to &lt;code&gt;join&lt;/code&gt; the tables and use &lt;code&gt;select&lt;/code&gt; to load the comments count within the &lt;code&gt;posts&lt;/code&gt; query:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;posts_with_counts =
  from(p in Post,
    left_join: c in Comment, on: c.post_id == p.id,
    group_by: [p.id],
    select: %{p | comments_count: count(c.id)}
  )
  |&amp;gt; Repo.all()

for post &amp;lt;- posts_with_counts do
  render(&amp;quot;post.html&amp;quot;, post: post, comments_count: post.comments_count)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To avoid and detect N+1 queries, developers must be vigilant when writing Ecto queries and templates.
Using &lt;code&gt;preload&lt;/code&gt; correctly to fetch all necessary records in a single database query is essential.&lt;/p&gt;
&lt;h2&gt;Detecting N+1 Queries By Their Impact&lt;/h2&gt;
&lt;p&gt;Understanding the data access patterns of your application can help you anticipate and prevent N+1 issues before they arise.
One way to identify N+1 queries is to observe and analyze common bottlenecks in your app, including:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Increased Load Times&lt;/strong&gt;: Each query takes time to execute, and when hundreds or thousands of them run sequentially, the cumulative effect leads to noticeable delays in content rendering.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database Strain&lt;/strong&gt;: Databases are designed to handle multiple queries efficiently, but an influx of unnecessary queries can strain the system, leading to slower response times for all users.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server Resource Drain&lt;/strong&gt;: A server&amp;#39;s resources are finite, and handling a multitude of queries consumes more CPU and memory, potentially affecting other operations and leading to resource exhaustion.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability Issues&lt;/strong&gt;: As a user base grows, inefficient N+1 queries can prevent an application from scaling smoothly, requiring more hardware resources to handle the same workload.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Implications&lt;/strong&gt;: Increased server load and database usage can lead to higher operational costs, especially in cloud-based environments where resources are metered.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, it is difficult to spot small differences in performance and then pinpoint the parts of your application that have caused such degradation.&lt;/p&gt;
&lt;p&gt;The next sections will show how AppSignal can help you detect and fix N+1 queries, ensuring your application runs smoothly and efficiently.&lt;/p&gt;
&lt;h2&gt;Detecting N+1 Queries in Phoenix for Elixir Using AppSignal&lt;/h2&gt;
&lt;p&gt;Before detecting N+1 queries, we need to set up AppSignal in your Phoenix application. &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;You can sign up for a free 30-day trial of AppSignal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;AppSignal provides an Elixir package that integrates seamlessly with Phoenix applications.
The &lt;a href=&quot;https://docs.appsignal.com/elixir/installation.html&quot;&gt;AppSignal for Elixir setup process&lt;/a&gt; involves adding the Elixir package to your project&amp;#39;s dependencies and configuring it with your AppSignal Push API key.
Once installed, AppSignal starts monitoring your application&amp;#39;s performance, including database query patterns.&lt;/p&gt;
&lt;h2&gt;Analyzing Elixir Data with AppSignal&lt;/h2&gt;
&lt;p&gt;AppSignal&amp;#39;s instrumentation for Phoenix and Ecto is designed to provide detailed insights into your application&amp;#39;s database interactions.
It automatically tracks database query times, helping you spot inefficiencies.
With AppSignal&amp;#39;s instrumentation in place, detecting N+1 queries becomes a matter of analyzing the collected data.&lt;/p&gt;
&lt;h3&gt;Use Slow Queries to Find N+1 Queries&lt;/h3&gt;
&lt;p&gt;AppSignal&amp;#39;s &lt;em&gt;Slow Queries&lt;/em&gt; dashboard breaks down web requests, showing the slowest queries and potential bottlenecks.
A series of similar queries within a single web request is a strong indicator of an N+1 query problem.&lt;/p&gt;
&lt;p&gt;For example, if you see repeated queries fetching comments for different posts while a blog page is being rendered, you&amp;#39;ve likely encountered an N+1 issue.
AppSignal provides context, including specific database calls, making it easier to pinpoint the exact location in your code where the issue originated.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-10/slow-queries.png&quot; alt=&quot;Screenshot of AppSignal Slow Queries Page&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We can see that the first query had almost 95% &lt;a href=&quot;https://docs.appsignal.com/appsignal/terminology.html#impact&quot;&gt;impact&lt;/a&gt; on all our queries executed through Ecto.
In a real-world app, this number might be lower, as there can be hundreds of unique queries. However, any outlier that&amp;#39;s highlighted here is a great candidate for analysis.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Note:&lt;/strong&gt; The &amp;quot;impact&amp;quot; of a query on an application is based on its usage compared to other queries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Another metric to consider here is the high throughput of &lt;code&gt;720&lt;/code&gt;.
Throughput is the total number of queries that were executed in a specified time window.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s check out the full details of the query:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT c0.&amp;quot;id&amp;quot;, c0.&amp;quot;body&amp;quot;, c0.&amp;quot;post_id&amp;quot;, c0.&amp;quot;user_id&amp;quot;, c0.&amp;quot;inserted_at&amp;quot;, c0.&amp;quot;updated_at&amp;quot;, c0.&amp;quot;post_id&amp;quot; FROM &amp;quot;comments&amp;quot; AS c0 WHERE (c0.&amp;quot;post_id&amp;quot; = $1) ORDER BY c0.&amp;quot;post_id&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since the query is targeting a single post, it is quite likely an N+1 query.&lt;/p&gt;
&lt;h3&gt;Trace N+1 Queries with the Event Timeline&lt;/h3&gt;
&lt;p&gt;AppSignal&amp;#39;s &lt;em&gt;Event Timeline&lt;/em&gt; is also particularly useful for finding and tracing N+1 queries.
It visualizes a sequence of database calls during a web request, allowing you to identify the hallmark successive database queries that characterize N+1 issues.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example event timeline for a page that has an N+1 query issue:
&lt;img src=&quot;/images/blog/2024-10/performance-get-posts-sample-event-timeline.png&quot; alt=&quot;Screenshot of AppSignal Performance Sample Event Timeline&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We can see that many quick queries are being performed.
Hovering over &lt;code&gt;query.ecto&lt;/code&gt; also shows the exact query that was performed to help us pinpoint which query is the culprit.&lt;/p&gt;
&lt;p&gt;Another good indication of a possible issue is when the &lt;code&gt;ecto&lt;/code&gt; time of an event is abnormally high.
For example, in this case, we can see that Ecto was the major time-hog:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-10/performance-get-posts-sample.png&quot; alt=&quot;Screenshot of AppSignal Performance Sample&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Addressing Detected N+1 Queries&lt;/h2&gt;
&lt;p&gt;Once you&amp;#39;ve identified an N+1 query with AppSignal, the next step is to address it.
This typically involves optimizing your Ecto queries to preload associated records.&lt;/p&gt;
&lt;p&gt;AppSignal&amp;#39;s detailed metrics allow you to compare performance before and after the changes, giving you concrete feedback on the impact of your optimizations.&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Whether you&amp;#39;re a seasoned developer or new to Phoenix, understanding the nuances of N+1 queries and leveraging AppSignal&amp;#39;s capabilities will empower you to build faster, more reliable applications.&lt;/p&gt;
&lt;p&gt;Remember, the key to maintaining a performant application is not just fixing issues as they arise, but continuously monitoring and improving your codebase with the help of powerful tools like AppSignal.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Complete Guide to Phoenix for Elixir Monitoring with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/09/17/a-complete-guide-to-phoenix-for-elixir-monitoring-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2024/09/17/a-complete-guide-to-phoenix-for-elixir-monitoring-with-appsignal.html</id>
    <published>2024-09-17T00:00:00+00:00</published>
    <updated>2024-09-17T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s set up monitoring and error reporting for a Phoenix application using AppSignal.</summary>
    <content type="html">&lt;p&gt;For Phoenix developers, maintaining the health of your applications is critical. AppSignal offers a powerful solution to gain deep insights into your application&amp;#39;s performance and stability.&lt;/p&gt;
&lt;p&gt;In this introductory guide, we&amp;#39;ll walk through the process of setting up AppSignal in your Phoenix app, instrumenting your code for detailed monitoring, handling errors effectively, and utilizing AppSignal&amp;#39;s features to maintain and improve your application&amp;#39;s performance. The lessons you learn from this article will help you get started using AppSignal to monitor your Phoenix app.&lt;/p&gt;
&lt;p&gt;But before proceeding, let&amp;#39;s see what you&amp;#39;ll need to follow along effectively.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;AppSignal account — you can sign up for a free 30-day trial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A Phoenix app to work with. If you don&amp;#39;t have one, you can fork &lt;a href=&quot;https://github.com/iamaestimo/intro-to-phoenix-monitoring-with-appsignal-example-app&quot;&gt;this one&lt;/a&gt; that we&amp;#39;ll use throughout the tutorial.&lt;/li&gt;
&lt;li&gt;Some experience working with Elixir/Phoenix applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s get started by learning how to add AppSignal to an existing Phoenix application.&lt;/p&gt;
&lt;h2&gt;Adding AppSignal to a Phoenix Application&lt;/h2&gt;
&lt;p&gt;Adding AppSignal&amp;#39;s Phoenix package is very easy — just open up &lt;code&gt;mix.exs&lt;/code&gt; and add the package as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
...
defp deps do
  [
    {:phoenix, &amp;quot;~&amp;gt; 1.7.14&amp;quot;},
    {:phoenix_ecto, &amp;quot;~&amp;gt; 4.5&amp;quot;},
    ...
    {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
  ]
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, run &lt;code&gt;mix deps.get&lt;/code&gt; to add the package to the application, then run the command below to install it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix appsignal.install &amp;lt;YOUR API KEY HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Tip: You can find your API key in the AppSignal dashboard.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When you run the installer, you&amp;#39;ll be prompted for an application name — go ahead and enter an appropriate name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Validating Push API key: Valid! 🎉
What is your application&amp;#39;s name? [counter_live_app]: Counter Live App
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next up, you&amp;#39;ll need to choose how you want the AppSignal configuration handled for your app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;There are two methods of configuring AppSignal in your application.
  Option 1: Using a &amp;quot;config/appsignal.exs&amp;quot; file. (1)
  Option 2: Using system environment variables.  (2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can choose whatever suits you, but I prefer option 1, which uses a config file that you can customize to your liking. Once you make your choice, the AppSignal configuration should now be working, and if you visit the dashboard, you can see some default graphs (these might be empty initially as it takes a little bit of time for your app&amp;#39;s data to be sent over).&lt;/p&gt;
&lt;p&gt;Before moving on, let&amp;#39;s take a look at how you can customize the AppSignal config file.&lt;/p&gt;
&lt;h2&gt;Customizing the AppSignal Config File&lt;/h2&gt;
&lt;p&gt;A config file tells AppSignal which app and environment to instrument.&lt;/p&gt;
&lt;p&gt;The code snippet below shows a minimal configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/appsignal.exs

import Config

config :appsignal, :config,
  otp_app: :counter_live_app,
  name: &amp;quot;Counter Live App&amp;quot;,
  push_api_key: &amp;quot;API KEY HERE&amp;quot;,
  env: Mix.env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the most important settings include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your application&amp;#39;s OTP name.&lt;/li&gt;
&lt;li&gt;The name of the app as you want it to appear on AppSignal.&lt;/li&gt;
&lt;li&gt;Your AppSignal API key.&lt;/li&gt;
&lt;li&gt;The environment you want to instrument for, which could be development, production, or test environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The config file can be further customized using a &lt;a href=&quot;https://docs.appsignal.com/elixir/configuration/options.html&quot;&gt;variety of other options&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With the installation and configuration working, let&amp;#39;s shift gears to monitor our Phoenix app&amp;#39;s performance.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Monitoring the Performance of a Phoenix App&lt;/h2&gt;
&lt;p&gt;When you add the AppSignal package to your Phoenix application, the package will take care of default HTTP instrumentation needs and send data to a dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/default-instrumentation.png&quot; alt=&quot;Default instrumentation&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And part of the automatic instrumentation includes performance monitoring:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/default-performance-monitoring.png&quot; alt=&quot;Default performance instrumentation&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The default instrumentation will also include important details for slow-performing requests, like what&amp;#39;s shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/automatic-performance-phoenix-dashboard.png&quot; alt=&quot;Automatic detailed performance dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And all of this is possible without any extra work from you.&lt;/p&gt;
&lt;p&gt;Next up, let&amp;#39;s see how you can customize some of the performance instrumentation. For example, we can add a custom slow function to the Posts index and see the same on the AppSignal dashboard.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s edit the index action in the posts controller as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/counter_live_app_web/controllers/posts_controller.ex

defmodule CounterLiveAppWeb.PostController do
  ...

  def index(conn, params) do
    really_slow()
    ...
  end
  ...
  def really_slow do
    Appsignal.instrument(&amp;quot;really slow index request&amp;quot;, fn -&amp;gt;
      :timer.sleep(1000)
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that, we can visualize the instrumentation on the dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/custom-performance-instrumentation.png&quot; alt=&quot;Custom performance instrumentation&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Tracking Phoenix App Errors Using AppSignal&lt;/h2&gt;
&lt;p&gt;In the previous section, we saw how adding AppSignal to our Phoenix app provides us with a lot of information about app performance. We also went ahead and added some simple custom instrumentation to simulate a really slow request to the posts index action, and visualized the results on the AppSignal dashboard. Now, let&amp;#39;s see how we can view and track Phoenix errors using AppSignal.&lt;/p&gt;
&lt;p&gt;Our first example will be a simple call to a non-existent route, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/ecto-no-result-error.png&quot; alt=&quot;Ecto no results error&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Again, as with the default performance metrics, without extra work on our part, AppSignal is able to pick up this error and display it on the dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/ecto-no-result-error-on-appsignal.png&quot; alt=&quot;Ecto no results error on AppSignal dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;If you click on the error, you can see more detailed information, which is really helpful for debugging purposes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/ecto-no-result-error-details.png&quot; alt=&quot;Ecto no results error details&quot;/&gt;&lt;/p&gt;
&lt;p&gt;I won&amp;#39;t go into more detail on how you can customize exception instrumentation in the scope of this post. If you are interested in going down that rabbit hole, &lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation/exception-handling.html&quot;&gt;check out the AppSignal for Elixir documentation on exception handling&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next up, let&amp;#39;s set up alerts and notifications.&lt;/p&gt;
&lt;h2&gt;Setting up Effective Alerts and Notifications&lt;/h2&gt;
&lt;p&gt;As useful as an application performance monitoring solution like AppSignal is, you wouldn&amp;#39;t want to spend all your time staring at dashboards. Instead, it would be better if you received automated alerts for any significant events.&lt;/p&gt;
&lt;p&gt;By default, whenever an error or performance event happens, it&amp;#39;s recorded as an error or performance incident by AppSignal. Depending on the notification settings you&amp;#39;ve set up, you&amp;#39;ll get an email (the default notification channel) or a message through any of the other &lt;a href=&quot;https://docs.appsignal.com/application/integrations&quot;&gt;available notification channels&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can customize how AppSignal will notify you of events and errors by setting up any of the five notification defaults available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Never notify&lt;/strong&gt; - when set to this, AppSignal will not notify you whenever an error or incident occurs. This setting is useful for non-critical incidents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every occurrence&lt;/strong&gt; - Let&amp;#39;s say you&amp;#39;d like to be notified every time an incident happens. This is the setting you would use. You can use this setting for incidents that are critical in nature.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First in deploy&lt;/strong&gt; - Here, a notification will be sent whenever an incident occurs when you first deploy your app. You will need to set up deploy markers that will tell AppSignal when a deployment occurs. For example, let&amp;#39;s say you&amp;#39;ve set up post-deploy hooks of some kind. In that case, this setting helps you catch errors if these hooks don&amp;#39;t work as expected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First after close&lt;/strong&gt; - This setting tells AppSignal to send a notification after an incident recurs, immediately after you close a previous similar one. This setting would be useful for incidents that are not entirely due to a bug in your code, (for example, third-party API connection issues and so forth).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every nth hour or day&lt;/strong&gt; - Here, you tell AppSignal not to send a notification every nth hour or day. This could be very useful if you are facing an increased bill due to an increase in notification events.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So far, everything we&amp;#39;ve looked at is quite basic, but your AppSignal setup is capable of a lot more.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s briefly look at one or two examples of custom monitoring and alert notification setups.&lt;/p&gt;
&lt;h2&gt;Custom Alert Notification Setup&lt;/h2&gt;
&lt;p&gt;By default, every application that is being monitored by AppSignal will have an email notifier set up automatically.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/default-email-notification-dashboard.png&quot; alt=&quot;Default email notification dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Even so, you might want to be notified via other channels, and with AppSignal, these are a breeze to set up. The first step is to click on the &amp;quot;Add integration&amp;quot; button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/setting-up-a-custom-notifier.png&quot; alt=&quot;Setting up a custom notifier - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;For example, if you wanted a Discord notifier, just choose it from the list of integrations and input the required information in the resulting dialog like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/setting-up-a-custom-notifier-discord.png&quot; alt=&quot;Setting up a Discord notifier&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Even with all the bells and whistles that AppSignal makes available for alerting and notifications, it&amp;#39;s important to really think about the kinds of notifications you would like to receive and the ones you&amp;#39;d be safe ignoring.&lt;/p&gt;
&lt;p&gt;Some good rules of thumb to guide your decision in this would include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider error thresholds for critical versus non-critical errors. For non-critical errors, you could set very high thresholds. For critical errors, you might set finer thresholds (for example, send an alert if a critical error exceeds 5% and lasts for more than 3 minutes).&lt;/li&gt;
&lt;li&gt;Set up alerts and notifications for memory consumption. One of the key resources any app uses is memory. If an app is consuming more-than-normal memory, you want to make sure an alert is sent to you early.&lt;/li&gt;
&lt;li&gt;Uptime and availability notifications. This is self-explanatory, but you definitely want to be notified any time your app is unavailable.&lt;/li&gt;
&lt;li&gt;It would also make sense to set up alerts for custom events that are key to the functionality of your app, or to the user experience (for example, a bunch of failed payments over a certain amount of time).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these rules in mind, and considering AppSignal&amp;#39;s robust alerting infrastructure, you have all you need to be notified whenever things go wrong. If you need further information, go through &lt;a href=&quot;https://docs.appsignal.com/application/integrations.html&quot;&gt;AppSignal&amp;#39;s documentation on setting up notifications and alerts&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Monitoring of a Phoenix App Using AppSignal: An Example&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll use AppSignal&amp;#39;s function decorators to set up a custom error span that will be fired when we try to request a non-existent post.&lt;/p&gt;
&lt;p&gt;First, we modify the posts controller to use AppSignal decorators like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/counter_live_app_web/controllers/post_controller.ex

defmodule CounterLiveAppWeb.PostController do
  use CounterLiveAppWeb, :controller
  use Appsignal.Instrumentation.Decorators # add this line

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we modify the show action with the custom instrumentation as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/counter_live_app_web/controllers/post_controller.ex

...
  def show(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}) do
    try do
      post = Blog.get_post!(id)
      render(conn, :show, post: post)
    rescue
      e in Ecto.NoResultsError -&amp;gt;
        Appsignal.send_error(e, __STACKTRACE__, fn span -&amp;gt;
          Appsignal.Span.set_name(span, &amp;quot;Custom Post Not Found Error&amp;quot;)
          Appsignal.Span.set_sample_data(span, &amp;quot;custom_data&amp;quot;, %{
            post_id: id,
            controller: &amp;quot;PostController&amp;quot;,
            action: &amp;quot;show&amp;quot;
          })
        end)

        conn
        |&amp;gt; put_status(:not_found)
        |&amp;gt; put_view(CounterLiveAppWeb.ErrorView)
        |&amp;gt; render(&amp;quot;404.html&amp;quot;)
    end
  end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use AppSignal&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/appsignal/Appsignal.Instrumentation.html#send_error/3&quot;&gt;&lt;code&gt;send_error/3&lt;/code&gt;&lt;/a&gt; to define a custom span with the name &amp;quot;Custom Post Not Found Error&amp;quot;, which is called if we make a request to a non-existent post.&lt;/p&gt;
&lt;p&gt;As you can see from the screenshots below, the error is captured as expected on AppSignal:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/custom-error-with-instrumentation.png&quot; alt=&quot;Custom error with instrumentation&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Clicking on the error link gives you access to the error details:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-09/custom-error-with-instrumentation-2.png&quot; alt=&quot;Custom error with instrumentation&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we&amp;#39;ve looked at how to set up AppSignal to monitor a Phoenix application. We also covered how errors and performance incidences are instrumented and displayed on the dashboard.&lt;/p&gt;
&lt;p&gt;Even though this is enough to get you started with monitoring your Phoenix application, AppSignal offers a lot more options for you to explore (such as Ecto-specific monitoring to cover your app&amp;#39;s Ecto queries, plug monitoring, and even in-depth custom instrumentation to cover almost any monitoring scenario you might have).&lt;/p&gt;
&lt;p&gt;Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Scaling Your Phoenix App in Elixir with FLAME</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/09/03/scaling-your-phoenix-app-in-elixir-with-flame.html"/>
    <id>https://blog.appsignal.com/2024/09/03/scaling-your-phoenix-app-in-elixir-with-flame.html</id>
    <published>2024-09-03T00:00:00+00:00</published>
    <updated>2024-09-03T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover the benefits of FLAME and see how it can offload intensive tasks to remote machines.</summary>
    <content type="html">&lt;p&gt;When you build an app, you&amp;#39;ll often find that certain tasks do not require user interaction and are better performed in the background.
Elixir provides excellent primitives, such as &lt;code&gt;Task.async&lt;/code&gt;, to offload these tasks from the main user pipeline. Additionally, libraries like Oban offer more control over background tasks when needed.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s also &lt;code&gt;FLAME&lt;/code&gt;, which the core Phoenix team is developing to offer a scalable solution for offloading intensive tasks to remote machines.&lt;/p&gt;
&lt;p&gt;We will compare these methods and see how FLAME stands out.&lt;/p&gt;
&lt;p&gt;But first, let&amp;#39;s delve into how FLAME works and how it can help you scale your Phoenix application.&lt;/p&gt;
&lt;h2&gt;Understanding FLAME for Phoenix&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;FLAME&lt;/code&gt; stands for &lt;em&gt;&lt;strong&gt;F&lt;/strong&gt;leeting &lt;strong&gt;L&lt;/strong&gt;ambda &lt;strong&gt;A&lt;/strong&gt;pplication for &lt;strong&gt;M&lt;/strong&gt;odular &lt;strong&gt;E&lt;/strong&gt;xecution&lt;/em&gt;.
It is similar to &lt;code&gt;Task.async&lt;/code&gt;, allowing you to run any block of code, but with the added benefit of executing it on a separate node.
Depending on your configuration, FLAME can automatically manage infrastructure, spawning or scaling down nodes as needed.&lt;/p&gt;
&lt;p&gt;To illustrate how FLAME works, let&amp;#39;s consider an example where we need to find the SHA-256 hash of a file stored on Amazon S3.
Calculating the hash for a large file can prove slow due to file size or network latency.
By offloading this task to a background worker with FLAME, we can improve the performance and responsiveness of our main application.&lt;/p&gt;
&lt;p&gt;Here’s how you can do it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;FLAME.call(MyApp.BackgroundRunner, fn -&amp;gt;
  ExAws.S3.download_file(bucket, file_path, :memory)
  |&amp;gt; ExAws.stream!()
  |&amp;gt; Enum.reduce(:crypto.hash_init(:sha256), fn chunk, acc -&amp;gt;
    :crypto.hash_update(acc, chunk)
  end)
  |&amp;gt; :crypto.hash_final()
  |&amp;gt; Base.encode16()
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is similar to &lt;code&gt;Task.async&lt;/code&gt; and &lt;code&gt;Task.await&lt;/code&gt;, with the key difference being that it runs on a separate node.
When the checksum is ready, it returns the result to the main node. We&amp;#39;ll discuss configuration options and available functions later in the post.&lt;/p&gt;
&lt;p&gt;So, how is this different from any background job processing framework (e.g., Oban)?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Built-in Scaling&lt;/strong&gt;: FLAME has built-in support for scaling.
It can automatically spawn new nodes when new tasks come in and scale down to zero (configurable) when no tasks are in the queue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal Boilerplate&lt;/strong&gt;: Unlike other frameworks, FLAME does not require extensive boilerplate code. You simply wrap your task inside &lt;code&gt;FLAME.call&lt;/code&gt; or &lt;code&gt;FLAME.cast&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Awaiting Results&lt;/strong&gt;: In most job frameworks (including the free version of Oban), you cannot await the result of background tasks. FLAME, however, supports this feature, allowing you to wait for a task&amp;#39;s completion and retrieve the result.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;FLAME in Action&lt;/h2&gt;
&lt;p&gt;In the previous section, we saw how easy it was to run a piece of code on a separate node using FLAME. Let&amp;#39;s pull back a little and see how to integrate FLAME inside an existing Phoenix app.&lt;/p&gt;
&lt;h3&gt;Install FLAME&lt;/h3&gt;
&lt;p&gt;Add the dependency in &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:flame, &amp;quot;~&amp;gt; 0.1.12&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Start a FLAME Pool&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;FLAME.Pool&lt;/code&gt; is the main &lt;code&gt;GenServer&lt;/code&gt; provided by FLAME that manages the scaling of nodes inside your app. It also schedules tasks and delivers results to each task&amp;#39;s respective nodes.&lt;/p&gt;
&lt;p&gt;Add &lt;code&gt;FLAME.Pool&lt;/code&gt; to your application&amp;#39;s supervision tree by updating the &lt;code&gt;application.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Application do
  use Application

  @half_hour_millis 1_800_000

  @impl true
  def start(_type, _args) do
    children =
      [
        # ...
        # The BackgroundRunner pool controlled by FLAME
        {FLAME.Pool, name: MyApp.BackgroundRunner, min: 0, max: 5, max_concurrency: 5, idle_shutdown_after: @half_hour_millis},
      ]
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; option defines the pool name to be used in calls to FLAME later in the application.
This allows you to define several different pools with different configurations depending on the tasks that you want to achieve.&lt;/p&gt;
&lt;p&gt;For example, for nodes that handle hash computation, you might want different concurrency settings than the nodes that handle more complex tasks, like video encoding.
&lt;a href=&quot;https://hexdocs.pm/flame/FLAME.Pool.html#start_link/1&quot;&gt;Check out all the available options for the pool&lt;/a&gt;. The most important ones that you will commonly use are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:min&lt;/code&gt; - The minimum number of nodes to start. You can configure this to zero to support pools that spawn a node only when there is a task, and then scale down when there are no pending tasks. This is especially useful in pre-production environments to save infrastructure costs.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:max&lt;/code&gt; - The maximum number of nodes at a time.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:max_concurrency&lt;/code&gt; - The maximum number of concurrent executions on a node.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:timeout&lt;/code&gt; - Default timeout for functions. This can also be set during individual calls (using &lt;code&gt;FLAME.call&lt;/code&gt; with the &lt;code&gt;timeout&lt;/code&gt; option).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:idle_shutdown_after&lt;/code&gt; - The number of seconds after which an idle node is shut down (only if there are more than the &lt;code&gt;min&lt;/code&gt; number of nodes).&lt;/li&gt;
&lt;/ul&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Configure FLAME Backend&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/flame/FLAME.Backend.html&quot;&gt;FLAME &lt;code&gt;Backend&lt;/code&gt;&lt;/a&gt; is the component responsible for starting up new nodes, connecting them to parent nodes, and running functions. By default, FLAME ships with the &lt;a href=&quot;https://hexdocs.pm/flame/FLAME.FlyBackend.html&quot;&gt;&lt;code&gt;FlyBackend&lt;/code&gt;&lt;/a&gt;. If you run your application on Fly, configuring FLAME is very simple. Just update your &lt;code&gt;config.exs&lt;/code&gt; or &lt;code&gt;runtime.exs&lt;/code&gt; if you use &lt;a href=&quot;https://hexdocs.pm/phoenix/releases.html&quot;&gt;Elixir releases&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flame, :backend, FLAME.FlyBackend

config :flame, FLAME.FlyBackend,
  token: System.fetch_env!(&amp;quot;FLY_API_TOKEN&amp;quot;),
  cpu_kind: System.get_env(&amp;quot;FLAME_CPU_KIND&amp;quot;, &amp;quot;shared&amp;quot;),
  memory_mb: System.get_env(&amp;quot;FLAME_MEMORY_MB&amp;quot;, &amp;quot;1024&amp;quot;) |&amp;gt; String.to_integer()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To access the Fly API for spawning or destroying machines, you need a token from Fly.
You can optionally configure the &lt;code&gt;cpu_kind&lt;/code&gt;, &lt;code&gt;memory&lt;/code&gt;, and &lt;code&gt;cpus&lt;/code&gt; for the spawned nodes.
Check out the full list of supported options in the &lt;a href=&quot;https://hexdocs.pm/flame/FLAME.FlyBackend.html&quot;&gt;&lt;code&gt;FlyBackend&lt;/code&gt; docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is also a &lt;a href=&quot;https://hexdocs.pm/flame_k8s_backend/readme.html&quot;&gt;&lt;code&gt;FLAMEK8sBackend&lt;/code&gt;&lt;/a&gt; available if you are running on Kubernetes.
If you are not using Kubernetes, other platforms have no out-of-the-box support.
However, you can refer to the &lt;a href=&quot;https://github.com/phoenixframework/flame/blob/main/lib/flame/fly_backend.ex&quot;&gt;&lt;code&gt;FLAME.FlyBackend&lt;/code&gt; code&lt;/a&gt; and create a similar backend for your platform.&lt;/p&gt;
&lt;h3&gt;Running Tasks with FLAME&lt;/h3&gt;
&lt;p&gt;FLAME provides two main functions for running tasks on other nodes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;FLAME.call/1&lt;/code&gt;&lt;/strong&gt;: This function calls a task on a remote node and waits for the result.
It&amp;#39;s useful when you need to run tasks in the background but still require a result.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;**Example**: A user requests a 10,000,000th Fibonacci number.
You can run the computation on another machine to avoid blocking web server resources while the user waits for the result.
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;FLAME.cast/1&lt;/code&gt;&lt;/strong&gt;: This function calls a task on a remote node without waiting for a result.
It&amp;#39;s useful when a result isn&amp;#39;t needed immediately and you don&amp;#39;t want to block the user pipeline.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;**Example**: After a user uploads a file, you want to update its checksum in the records.
This can be done in the background without making the user wait.
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By default, the spawned processes on the remote node are linked to the parent process, preventing orphaned tasks on remote nodes if the parent process is killed or dies.
However, for some background tasks (e.g., file checksum generation), it might be useful to continue running a task even if the parent process is terminated.&lt;/p&gt;
&lt;p&gt;Both &lt;code&gt;FLAME.call/2&lt;/code&gt; and &lt;code&gt;FLAME.cast/2&lt;/code&gt; support a &lt;code&gt;link&lt;/code&gt; option that can be set to &lt;code&gt;false&lt;/code&gt; to achieve this.&lt;/p&gt;
&lt;h3&gt;Deploying FLAME&lt;/h3&gt;
&lt;p&gt;You don&amp;#39;t need anything special to deploy FLAME as long as you have configured a backend with all the required properties.
FLAME starts your full application supervision tree on the remote node.
Some parts of the application might not be necessary on a worker node.
To control this, you can use &lt;a href=&quot;https://hexdocs.pm/flame/FLAME.Parent.html#get/0&quot;&gt;&lt;code&gt;FLAME.Parent.get/0&lt;/code&gt;&lt;/a&gt; to determine if an application is running on the main node or a child node.
Update &lt;code&gt;application.ex&lt;/code&gt; to add children to your supervision tree only if they are on the main node (i.e., if &lt;code&gt;FLAME.parent.get()&lt;/code&gt; is &lt;code&gt;nil&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    flame_instance? = not is_nil(FLAME.Parent.get())
    children = [
      # ...
      {FLAME.Pool, name: MyApp.BackgroundRunner, min: 0, max: 5, max_concurrency: 5, idle_shutdown_after: @half_hour_millis},
      !flame_instance? &amp;amp;&amp;amp; MyAppWeb.Endpoint
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Technical Deep Dive into FLAME&lt;/h2&gt;
&lt;p&gt;Internally, FLAME leverages Elixir&amp;#39;s powerful &lt;a href=&quot;https://hexdocs.pm/elixir/1.16.3/Node.html#spawn_monitor/4&quot;&gt;&lt;code&gt;Node.spawn_monitor/4&lt;/code&gt;&lt;/a&gt; function for spawning processes on remote nodes.
This, coupled with BEAM&amp;#39;s closure behavior, forms the core of FLAME&amp;#39;s implementation.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s delve into what occurs under the hood when you execute &lt;code&gt;FLAME.cast&lt;/code&gt; or &lt;code&gt;FLAME.call&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The request is dispatched to a pool of runners.&lt;/li&gt;
&lt;li&gt;If a runner is readily available (based on defined constraints like &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;, etc.), it spawns and monitors the process on the remote node.&lt;ul&gt;
&lt;li&gt;Upon successful execution, the result is returned or discarded depending on the operation used.&lt;/li&gt;
&lt;li&gt;Additionally, it monitors the process according to the timeout configuration and terminates it if necessary.&lt;/li&gt;
&lt;li&gt;If the remote node crashes (e.g., due to memory exhaustion), the parent process is notified or terminated as per the configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If a process cannot be accommodated on an existing remote node, FLAME tries to spawn a new node (using the configured backend) within the specified limits.&lt;ul&gt;
&lt;li&gt;Once the node is spawned, it follows the same steps as mentioned in (2).&lt;/li&gt;
&lt;li&gt;If spawning a new node fails (e.g., because the maximum limit is reached), the task is queued until resources become available.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Regardless of specific user calls, FLAME autonomously manages idle nodes based on the configuration, shutting them down as needed using the configured backend.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Understanding Closures&lt;/h3&gt;
&lt;p&gt;Closures play a pivotal role in FLAME&amp;#39;s operation, and understanding them is essential in BEAM programming.
A closure captures its enclosing environment, including variables from the outer scope.
When a closure is defined, it retains references to the variables it &amp;quot;closes over&amp;quot;, thus preserving the state of its enclosing process.
This behavior is crucial for maintaining consistency, even in scenarios where a process crashes and restarts.&lt;/p&gt;
&lt;p&gt;However, when transmitting closures across different nodes in BEAM, the code on all nodes must match precisely.
The Fly backend addresses this requirement well, as deployments on Fly rely on Docker images of the released code.
This ensures uniformity between the parent node and the remote node, facilitating seamless execution of FLAME.&lt;/p&gt;
&lt;h3&gt;Leveraging Files as Processes&lt;/h3&gt;
&lt;p&gt;Things get more interesting when we explore the concept of treating files as processes.
In Elixir, opening a file spawns a new process. Writing to a file is akin to sending messages to the process handling the file descriptor.
This behavior extends to functions like &lt;a href=&quot;https://hexdocs.pm/elixir/1.16.3/File.html#stream!/3&quot;&gt;&lt;code&gt;File.stream!&lt;/code&gt;&lt;/a&gt; and all other file operations.
Consequently, we can extend FLAME&amp;#39;s capabilities to handle scenarios such as computing checksums of files stored on S3 or even supporting user-uploaded files directly on the web server.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a code sample:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;stream = File.stream!(file_path) # this runs on the web server
FLAME.call(MyApp.BackgroundRunner, fn -&amp;gt;
  # this runs on the remote machine
  stream
  |&amp;gt; Enum.reduce(:crypto.hash_init(:sha256), fn chunk, acc -&amp;gt;
    :crypto.hash_update(acc, chunk)
  end)
  |&amp;gt; :crypto.hash_final()
  |&amp;gt; Base.encode16()
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this scenario, the file stream is initiated on the source machine, while the checksum computation is offloaded to the remote worker.
This setup capitalizes on Elixir and BEAM&amp;#39;s handling of closures and processes.
However, it&amp;#39;s worth noting that a more efficient approach would involve establishing a shared volume accessible from both nodes.
A shared volume minimizes resource usage and enhances performance. This is in contrast to utilizing the stream from the main node, which still consumes resources to transmit data to the remote node.&lt;/p&gt;
&lt;h2&gt;Comparing FLAME With Other Approaches&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s now see how FLAME stacks up against some alternative approaches.&lt;/p&gt;
&lt;h3&gt;Running Background Tasks on the Same Node&lt;/h3&gt;
&lt;p&gt;Using &lt;code&gt;Task.async&lt;/code&gt; and similar functions, your tasks run on the same node as your web server.
This approach works well for quick, lightweight tasks.
However, during periods of heavy load, these background tasks can compete with your web server for resources, potentially slowing down your application&amp;#39;s response time.&lt;/p&gt;
&lt;h3&gt;Using Oban for Elixir to Get More Control&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/oban/Oban.html&quot;&gt;Oban&lt;/a&gt; is a powerful library that allows you to manage background jobs with more granularity. It enables you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Define dedicated Oban Workers.&lt;/li&gt;
&lt;li&gt;Configure job queues.&lt;/li&gt;
&lt;li&gt;Set up a job storage backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oban also supports running these tasks on dedicated nodes, which can help reduce the load on your main web server.
However, setting up Oban involves significant boilerplate code. In its free version, it does not support automatic scaling of the physical nodes running the jobs.&lt;/p&gt;
&lt;h3&gt;Achieving Infinite Scale with Serverless Functions&lt;/h3&gt;
&lt;p&gt;For truly infinite scalability, you can use external serverless functions like AWS Lambda, Google Cloud Functions, or Azure Functions.
These services allow you to run background tasks independently of your main application infrastructure.
However, they come with their own set of challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Significant boilerplate and context switching for developers.&lt;/li&gt;
&lt;li&gt;Synchronization issues between third-party services and your application code.&lt;/li&gt;
&lt;li&gt;Potential latency and cold start problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;FLAME: A Summary&lt;/h3&gt;
&lt;p&gt;As we have seen, &lt;code&gt;FLAME&lt;/code&gt; provides a robust way to handle complex background tasks at scale &lt;strong&gt;within&lt;/strong&gt; your Phoenix app.
It aims to simplify the setup process and reduce boilerplate code, offering an efficient and scalable solution.
All of this comes without the need to context switch — you can call FLAME code from within your app.&lt;/p&gt;
&lt;p&gt;By using FLAME, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Easily offload tasks from the main user pipeline.&lt;/li&gt;
&lt;li&gt;Manage and scale background jobs without extensive configuration.&lt;/li&gt;
&lt;li&gt;Improve your application&amp;#39;s performance and responsiveness during heavy loads.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we&amp;#39;ve explored how to scale your Phoenix application using FLAME.
We&amp;#39;ve delved into how FLAME stands out by offloading tasks to remote nodes. It also offers built-in scaling with minimal boilerplate code.
We&amp;#39;ve compared FLAME with other methods, too, like &lt;code&gt;Task.async&lt;/code&gt;, Oban, and external serverless functions, highlighting its unique advantages.&lt;/p&gt;
&lt;p&gt;Ultimately, FLAME helps you build more robust and scalable applications by leveraging Elixir&amp;#39;s strengths in concurrency and distributed computing, all while keeping your development process straightforward and intuitive.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>LiveState for Elixir: An Overview and How to Build Embeddable Web Apps</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/08/20/livestate-for-elixir-an-overview-and-how-to-build-embeddable-web-apps.html"/>
    <id>https://blog.appsignal.com/2024/08/20/livestate-for-elixir-an-overview-and-how-to-build-embeddable-web-apps.html</id>
    <published>2024-08-20T00:00:00+00:00</published>
    <updated>2024-08-20T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn how to build robust and dynamic embeddable web apps using LiveState for Elixir.</summary>
    <content type="html">&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.
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&amp;#39;s state.
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&amp;#39;ll build a LiveState component to manage a to-do list.
We&amp;#39;ll also build a Phoenix channel backend and use LitElement for our front-end component.
The front-end component will mostly be plumbing — we&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TodoApp.MixProject do
  use Mix.Project

  defp deps do
    [
      # ...
      {:live_state, &amp;quot;~&amp;gt; 0.8.1&amp;quot;},
      {:cors_plug, &amp;quot;~&amp;gt; 3.0&amp;quot;}
    ]
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TodoAppWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :todo_app

  socket &amp;quot;/socket&amp;quot;, TodoAppWeb.LiveStateSocket
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TodoAppWeb.LiveStateSocket do
  use Phoenix.Socket

  channel &amp;quot;todos:*&amp;quot;, TodoAppWeb.TodosChannel
  @impl true
  def connect(_params, socket), do: {:ok, socket}

  @impl true
  def id(_), do: &amp;quot;todos:*&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a standard Phoenix Socket.
If you have worked with &lt;a href=&quot;https://hexdocs.pm/phoenix/channels.html&quot;&gt;channels&lt;/a&gt; before, you may already be familiar with how this works.
For new users, the &lt;a href=&quot;https://hexdocs.pm/phoenix/Phoenix.Socket.html#channel/3&quot;&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&amp;#39;s define the channel.
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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TodoAppWeb.TodosChannel do
  use LiveState.Channel, web_module: TodoAppWeb

  alias LiveState.Event

  @impl true
  def init(_channel, _payload, _socket) do
    {:ok, %{todos: list_todos()}}
  end

  defp list_todos() do
    Todos.list_todos()
    |&amp;gt; Enum.map(&amp;amp;todo/1)
  end

  defp todo(%Todos.Todo{} = todo), do: Map.take(todo, [:id, :title, :completed])
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the most basic setup for the channel.
Let&amp;#39;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&amp;#39;s look at the final part of our setup: the client component.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Build the Front-End Component with &lt;code&gt;LitElement&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll use &lt;a href=&quot;https://lit.dev/&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# assets
$ npm install lit phx-live-state --save
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;If you are new to &lt;code&gt;LitElement&lt;/code&gt; and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// assets/js/modules/todos/TodoListElement.ts
import { html, LitElement } from &amp;quot;lit&amp;quot;;
import { customElement, property, state } from &amp;quot;lit/decorators.js&amp;quot;;
import LiveState, { connectElement } from &amp;quot;phx-live-state&amp;quot;;

type Todo = {
  id: number;
  title: string;
  completed: boolean;
};

@customElement(&amp;quot;todo-list&amp;quot;)
export class TodoListElement extends LitElement {
  @property({ type: String })
  url: string = &amp;quot;&amp;quot;;

  @state()
  todos: Array&amp;lt;Todo&amp;gt; = [];

  connectedCallback() {
    super.connectedCallback();
    const liveState = new LiveState({
      url: this.url,
      topic: `todos:${window.location.href}`,
    });

    connectElement(liveState, this, {
      properties: [&amp;quot;todos&amp;quot;],
    });
  }

  render() {
    return html`
      &amp;lt;ul style=&amp;quot;list-style-type: none&amp;quot;&amp;gt;
        ${this.todos?.map(
          (todo) =&amp;gt; html`
            &amp;lt;li&amp;gt;
              &amp;lt;input
                type=&amp;quot;checkbox&amp;quot;
                id=${`todo-${todo.id}`}
                ?checked=${todo.completed}
              /&amp;gt;
              &amp;lt;label for=${`todo-${todo.id}`}&amp;gt;${todo.title}&amp;lt;/label&amp;gt;
            &amp;lt;/li&amp;gt;
          `,
        )}
      &amp;lt;/ul&amp;gt;
    `;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;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&amp;#39;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&amp;#39;s URL.
Using the page&amp;#39;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&amp;#39;s JavaScript file (&lt;code&gt;assets/js/app.js&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;import &amp;quot;./modules/todos/TodoListElement&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will make the component available for use.
Since we configured it as a custom HTML element, it&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;todo-list url=&amp;quot;ws://127.0.0.1:4000/socket&amp;quot;&amp;gt;&amp;lt;/todo-list&amp;gt;
&lt;/code&gt;&lt;/pre&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&amp;#39;s add a way to create new to-dos.&lt;/p&gt;
&lt;p&gt;First, we&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;connectedCallback() {
  // ...
  connectElement(liveState, this, {
    properties: [&amp;#39;todos&amp;#39;],
    events: {
      send: [&amp;#39;add_todo&amp;#39;],
      receive: [&amp;#39;todo_created&amp;#39;]
    }
  });
}
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;render() {
  return html`
    &amp;lt;ul style=&amp;quot;list-style-type: none&amp;quot;&amp;gt;
      ${this.todos?.map(todo =&amp;gt; html`
        &amp;lt;li&amp;gt;
          &amp;lt;input type=&amp;quot;checkbox&amp;quot; id=${`todo-${todo.id}`} ?checked=${todo.completed}&amp;gt;
          &amp;lt;label for=${`todo-${todo.id}`}&amp;gt;${todo.title}&amp;lt;/label&amp;gt;
        &amp;lt;/li&amp;gt;
      `)}
    &amp;lt;/ul&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;form @submit=${this.addTodo}&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;label for=&amp;quot;todo&amp;quot;&amp;gt;Todo&amp;lt;/label&amp;gt;
          &amp;lt;input id=&amp;quot;todo&amp;quot; name=&amp;quot;title&amp;quot; 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;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that we referenced the &lt;code&gt;addTodo&lt;/code&gt; method in the form&amp;#39;s &lt;code&gt;@submit&lt;/code&gt; callback.
Let&amp;#39;s add that method as well:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;@query(&amp;#39;input[name=&amp;quot;title&amp;quot;]&amp;#39;)
titleInput: HTMLInputElement | undefined;

addTodo(e: Event) {
  this.dispatchEvent(new CustomEvent(&amp;#39;add_todo&amp;#39;, {
    detail: {
      title: this.titleInput?.value
    }
  }));
  e.preventDefault();
}
&lt;/code&gt;&lt;/pre&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&amp;#39;s go back to the &lt;code&gt;TodosChannel&lt;/code&gt; and add this functionality.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule TodoAppWeb.TodosChannel do
  alias LiveState.Event

  @impl true
  def handle_event(&amp;quot;add_todo&amp;quot;, todo_params, %{todos: todos}) do
    case Todos.create_todo(todo_params) do
      {:ok, t} -&amp;gt;
        data = todo(t)
        {:reply, [%Event{name: &amp;quot;todo_created&amp;quot;, detail: data}], %{todos: todos ++ [data]}}
    end
  end
end
&lt;/code&gt;&lt;/pre&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&amp;#39;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=&quot;https://hexdocs.pm/live_state/LiveState.Event.html&quot;&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&amp;#39;t go into those in this post.
If you&amp;#39;re interested, &lt;a href=&quot;https://github.com/pulkit110/live-state-todos&quot;&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&amp;#39;ll notice that we integrated a component directly into a Phoenix app.
In a typical Phoenix app, there&amp;#39;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&amp;#39;s configuration.
We&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;// app/js/modules/todos/index.ts
import &amp;quot;./TodoListElement&amp;quot;;
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :esbuild,
  version: &amp;quot;0.17.11&amp;quot;,
  # this is the default entrypoint that phoenix generates
  todo_app: [
    args:
      ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
    cd: Path.expand(&amp;quot;../assets&amp;quot;, __DIR__),
    env: %{&amp;quot;NODE_PATH&amp;quot; =&amp;gt; Path.expand(&amp;quot;../deps&amp;quot;, __DIR__)}
  ],
  # add a new config that bundles only the modules/todos/index.ts file
  todos: [
    args:
      ~w(js/modules/todos/index.ts --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
    cd: Path.expand(&amp;quot;../assets&amp;quot;, __DIR__),
    env: %{&amp;quot;NODE_PATH&amp;quot; =&amp;gt; Path.expand(&amp;quot;../deps&amp;quot;, __DIR__)}
  ]
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :todo_app, TodoAppWeb.Endpoint,
  # other endpoint config
  watchers: [
    # ...
    # the default watched generated by phoenix
    esbuild: {Esbuild, :install_and_run, [:todo_app, ~w(--sourcemap=inline --watch)]},
    # a new watcher that just watches the todo element (matches the `todos` from config.exs)
    esbuild_todos: {Esbuild, :install_and_run, [:todos, ~w(--sourcemap=inline --watch)]}
  ]
&lt;/code&gt;&lt;/pre&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&amp;#39;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=&quot;https://launchscout.github.io/phx-live-state/&quot;&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=&quot;https://github.com/launchscout/use-live-state&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;export function TodoList() {
  const [state, pushEvent] = useLiveState(liveState, {});
  return (
    &amp;lt;ul style=&amp;quot;list-style-type: none&amp;quot;&amp;gt;
      ${state.todos?.map((todo) =&amp;gt; (
        &amp;lt;li key={todo.id}&amp;gt;
          &amp;lt;input type=&amp;quot;checkbox&amp;quot; id={`todo-${todo.id}`} checked={todo.completed}&amp;gt;
          &amp;lt;label for={`todo-${todo.id}`}&amp;gt;{todo.title}&amp;lt;/label&amp;gt;
        &amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;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&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Custom Instrumentation for a Phoenix App in Elixir with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/08/06/custom-instrumentation-for-a-phoenix-app-in-elixir-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2024/08/06/custom-instrumentation-for-a-phoenix-app-in-elixir-with-appsignal.html</id>
    <published>2024-08-06T00:00:00+00:00</published>
    <updated>2024-08-06T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of this two-part series, we&#039;ll set up custom instrumentation for a Phoenix application using AppSignal.</summary>
    <content type="html">&lt;p&gt;In the first part of this series, we saw that even if you just use AppSignal’s default application monitoring, you can get a lot of information about how your Phoenix application is running.&lt;/p&gt;
&lt;p&gt;Even so, there are many ways in which a Phoenix application may exhibit performance issues, such as slow database queries, poorly engineered LiveView components, views that are too heavy, or non-optimized assets.&lt;/p&gt;
&lt;p&gt;To get a grasp on such issues and peer even more closely into your app’s internals, you’ll need something that packs more punch than the default dashboards: custom instrumentation.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll go through a step-by-step process to build custom instrumentation using AppSignal for a Phoenix application.&lt;/p&gt;
&lt;h2&gt;Pre-requisites&lt;/h2&gt;
&lt;p&gt;Before we get into custom instrumentation, here&amp;#39;s what you need to follow along:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Phoenix LiveView app with the AppSignal package installed. If you have an app ready but haven&amp;#39;t installed the AppSignal package, just &lt;a href=&quot;https://docs.appsignal.com/elixir/installation.html&quot;&gt;follow this guide&lt;/a&gt;. Or you can &lt;a href=&quot;https://github.com/iamaestimo/game_reviews_liveview&quot;&gt;clone the Phoenix app we&amp;#39;ll be using&lt;/a&gt; throughout the tutorial.&lt;/li&gt;
&lt;li&gt;Basic experience working with Elixir and the Phoenix framework.&lt;/li&gt;
&lt;li&gt;An AppSignal account. &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;Sign up for a free trial&lt;/a&gt; if you don&amp;#39;t have one already.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What Is Custom Instrumentation, and Why Do We Need It?&lt;/h2&gt;
&lt;p&gt;Custom instrumentation means adding additional telemetry emission and monitoring functionality to your Phoenix app beyond what is provided by the default instrumentation. Specifically, it involves the use of functions and macros (provided through the AppSignal package) in specific places in your codebase that you want to investigate further. You can then view the collected data on a custom AppSignal dashboard.&lt;/p&gt;
&lt;p&gt;If you have a complex or mission-critical Phoenix app, it might not be possible to identify all its potential performance issues using the default instrumentation. It&amp;#39;s important to have deeper insights into what&amp;#39;s going on inside your app.&lt;/p&gt;
&lt;p&gt;With custom instrumentation, you can easily structure exactly what you need to identify and visualize these custom data collections within the AppSignal dashboard.&lt;/p&gt;
&lt;h2&gt;Getting Started with Custom Instrumentation in AppSignal&lt;/h2&gt;
&lt;p&gt;You can implement &lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation/instrumentation.html&quot;&gt;custom instrumentation using AppSignal&lt;/a&gt; in two ways: through function decorators or instrumentation helpers.&lt;/p&gt;
&lt;h3&gt;Function Decorators&lt;/h3&gt;
&lt;p&gt;A function decorator is a higher-order function that you wrap around a function from which you want to collect data. They give you more granular control than instrumentation helpers, but compared to the latter, they are not as flexible.&lt;/p&gt;
&lt;h3&gt;Instrumentation Helpers&lt;/h3&gt;
&lt;p&gt;AppSignal also provides instrumentation helper functions, which you can use to instrument specific parts of your code manually. These helper functions can start and stop custom measurements, help you track custom events, and add custom metadata to metrics reported via AppSignal dashboards. This approach gives you more flexibility in instrumenting your code but requires more manual intervention.&lt;/p&gt;
&lt;p&gt;In the following sections, we&amp;#39;ll use what we&amp;#39;ve learned to implement custom instrumentation for a Phoenix application.&lt;/p&gt;
&lt;h2&gt;How to Use an Instrumentation Helper&lt;/h2&gt;
&lt;p&gt;To implement the first custom instrumentation, we&amp;#39;ll consider a controller action that calls a potentially slow function in a simple Phoenix app featuring games and reviews.&lt;/p&gt;
&lt;p&gt;As you can see below, the games context has a method for fetching an individual game and preloading any reviews:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app/games.ex

...
def get_game_with_reviews(id), do: Repo.get(Game, id) |&amp;gt; Repo.preload([:reviews])
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the subsequent action using this method in the game controller is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app_web/controllers/game_controller.ex

...
def show(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}) do
  game=Games.get_game_with_reviews(id)
  render(conn, :show, game: game)
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s modify this controller action with a custom instrumentation helper to check how many times it is called and its response times. We can do this using AppSignal&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/appsignal/Appsignal.Instrumentation.Helpers.html#summary&quot;&gt;&lt;code&gt;instrument/2&lt;/code&gt;&lt;/a&gt; function, which takes two parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The function name&lt;/li&gt;
&lt;li&gt;The function being instrumented&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; If you use &lt;code&gt;instrument/3&lt;/code&gt; instead, it&amp;#39;s possible to add an event group name as an optional parameter. Usually, whenever you use &lt;code&gt;instrument/2&lt;/code&gt;, measurements will be collected and categorized under the &amp;quot;other&amp;quot; event group within the event groups section. But if you wanted another more descriptive name, &lt;code&gt;instrument/3&lt;/code&gt; allows you to pass in an additional parameter for the event group name.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app_web/controllers/game_controller.ex

defmodule GameReviewsAppWeb.GameController do
  use GameReviewsAppWeb, :controller

  ...

  def show(conn, %{&amp;quot;id&amp;quot;=&amp;gt;id}) do
    game = Games.get_game_with_reviews(id)
    am_i_slow() # add this line
    render(conn, :show, game: game)
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Let&amp;#39;s define the &lt;code&gt;am_i_slow&lt;/code&gt; function as a private module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app_web/controllers/game_controller.ex

defmodule GameReviewsAppWeb.GameController do
  use GameReviewsAppWeb, :controller

  ...
  defp am_i_slow do
    Appsignal.instrument(&amp;quot;Check if am slow&amp;quot;, fn-&amp;gt;
      :timer.sleep(1000)
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Specifically, we&amp;#39;re defining a custom trace span with an event sample called &lt;code&gt;&amp;quot;Check if am slow&amp;quot;&lt;/code&gt;. This will show up in our dashboard under the &lt;em&gt;other&lt;/em&gt; (background) event namespace, as you can see in the screenshots below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-08/instrument-helper-1.png&quot; alt=&quot;Custom instrumentation using an instrumentation helper - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-08/instrument-helper-2.png&quot; alt=&quot;Custom instrumentation using an instrumentation helper - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-08/instrument-helper-3.png&quot; alt=&quot;Custom instrumentation using an instrumentation helper - 3&quot;/&gt;&lt;/p&gt;
&lt;p&gt;But what if you wanted a different event group name from &lt;code&gt;&amp;quot;other&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;background&amp;quot;&lt;/code&gt; for the event namespace? Just use the &lt;code&gt;instrument/3&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app_web/controllers/game_controller.ex

defmodule GameReviewsAppWeb.GameController do
  use GameReviewsAppWeb, :controller

  ...
  defp am_i_slow do
    Appsignal.instrument(&amp;quot;Really Slow Queries&amp;quot;,&amp;quot;First Slow Query&amp;quot;, fn-&amp;gt;
      :timer.sleep(1000)
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we give the span a category name of &lt;code&gt;&amp;quot;Really Slow Queries&amp;quot;&lt;/code&gt; and a span name of &lt;code&gt;&amp;quot;First Slow Query&amp;quot;&lt;/code&gt;, for a sample view like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-08/instrument-helper-4.png&quot; alt=&quot;Instrumentation helper with custom category name&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s another example of using function helpers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app_web/controllers/game_controller.ex

defmodule GameReviewsAppWeb.GameController do
  use GameReviewsAppWeb, :controller

  ...
  def index(conn,_params) do
    games = Appsignal.instrument(&amp;quot;Fetch games&amp;quot;, fn-&amp;gt;
    Games.list_games()
  end)

  render(conn, :index, games: games)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the &lt;code&gt;instrument/2&lt;/code&gt; function, we define a span called &lt;code&gt;&amp;quot;Fetch games&amp;quot;&lt;/code&gt; which results in this event trace:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-08/instrument-helper-5.png&quot; alt=&quot;Instrumentation helper - 5&quot;/&gt;&lt;/p&gt;
&lt;p&gt;With that, you can easily visualize the function&amp;#39;s response time and throughput.&lt;/p&gt;
&lt;p&gt;There are &lt;a href=&quot;https://hexdocs.pm/appsignal/Appsignal.Span.html&quot;&gt;more options available to customize AppSignal&amp;#39;s instrumentation helpers&lt;/a&gt; than what I&amp;#39;ve shown here. I highly encourage you to check out the possibilities.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s see how you can use function decorators.&lt;/p&gt;
&lt;h2&gt;Using Function Decorators&lt;/h2&gt;
&lt;p&gt;As you&amp;#39;ve probably noticed when using instrumentation helpers, you end up modifying existing functions with the helper code you add. If you don&amp;#39;t want to do this, you can use function decorators instead.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s continue working with the game controller and instrument the index method using a decorator. First, we will add the decorator module &lt;code&gt;Appsignal.Instrumentation.Decorators&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app_web/controllers/game_controller.ex

defmodule GameReviewsAppWeb.GameController do
  ...
  use Appsignal.Instrumentation.Decorators
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You now have access to the decorator&amp;#39;s functions. Let&amp;#39;s decorate the index method as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app_web/controllers/game_controller.ex

defmodule GameReviewsAppWeb.GameController do
  ...
  use Appsignal.Instrumentation.Decorators
     
  def show(conn, %{&amp;quot;id&amp;quot;=&amp;gt;id}) do
    am_i_slow()
    game = Games.get_game_with_reviews(id)
    render(conn,:show,game:game)
  end

  # add the decorator function
  @decorate transaction_event()
  defp am_i_slow do
    :timer.sleep(1000)
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a transaction event, which you can visualize in your &lt;em&gt;Events&lt;/em&gt; dashboard, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-08/function-decorator-1.png&quot; alt=&quot;Function decorator - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You get all the information you need, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a. The resource where the function decorator was called&lt;/li&gt;
&lt;li&gt;b. A sample breakdown showing how long Ecto queries took, how long the templates took to load, and so forth.&lt;/li&gt;
&lt;li&gt;c. An event timeline with a breakdown of the transaction time of everything involved in that function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, let&amp;#39;s take a look at instrumenting Phoenix channels.&lt;/p&gt;
&lt;h2&gt;Instrumenting Phoenix LiveViews and Channels&lt;/h2&gt;
&lt;p&gt;In the example below, we have the welcome live view as shown:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# game_reviews_app_web/live/welcome_live.ex

defmodule GameReviewsAppWeb.WelcomeLive do
  use GameReviewsAppWeb, :live_view

  def mount(_params,_session,socket) do
    {:ok,assign(socket, current_time: DateTime.utc_now())}
  end

  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
      &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;
        &amp;lt;h1&amp;gt;Welcome to my LiveView App&amp;lt;/h1&amp;gt;
        &amp;lt;p&amp;gt;Current time: &amp;lt;%= @current_time %&amp;gt;&amp;lt;/p&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s use an instrumentation helper to see how this live view performs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# game_reviews_app_web/live/welcome_live.ex

defmodule GameReviewsAppWeb.WelcomeLive do
  ...

  import Appsignal.Phoenix.LiveView,only:[instrument: 4]

  def mount(_params,_session,socket) do
    instrument(__MODULE__,&amp;quot;Liveview instrumentation&amp;quot;, socket, fn-&amp;gt;
      :timer.send_interval(1000,self(),:tick)
      {
        :ok,
        assign(socket,current_time:DateTime.utc_now())
      }
    end)
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And as you can see, the transaction times and throughput are now available for inspection on our dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-08/instrumenting-liveviews.png&quot; alt=&quot;Instrumenting Liveviews&quot;/&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also worth noting that the AppSignal for Elixir package enables you to instrument Phoenix channels using a custom function decorator:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GameReviewsAppWeb.VideoChannel do
  use GameReviewsAppWeb, :channel

  # first add the instrumentation decorators module
  use Appsignal.Instrumentation.Decorators

  # then add the decorator function
  @decorate channel_action()
  def join(&amp;quot;videos:&amp;quot; &amp;lt;&amp;gt; video_id, _params, socket) do
    {:ok,assign(socket, :video_id, String.to_integer(video_id))}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In part one of this series, we looked at how to set up AppSignal for an Elixir app and AppSignal&amp;#39;s error tracking functionality.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ve seen how easy it is to use AppSignal&amp;#39;s Elixir package to implement custom instrumentation for a Phoenix application. We&amp;#39;ve also learned how to use instrumentation helpers and function decorators.&lt;/p&gt;
&lt;p&gt;With this information, you can now easily decide when to use a decorator versus an instrumentation helper in your next Phoenix app.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Enhancing Your Elixir Codebase with Gleam</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/07/23/enhancing-your-elixir-codebase-with-gleam.html"/>
    <id>https://blog.appsignal.com/2024/07/23/enhancing-your-elixir-codebase-with-gleam.html</id>
    <published>2024-07-23T00:00:00+00:00</published>
    <updated>2024-07-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s look at the benefits of using Gleam and then add Gleam code to an Elixir project.</summary>
    <content type="html">&lt;p&gt;Do you write Elixir but sometimes miss the benefits of type safety we have in other languages? If the answer is &amp;quot;yes&amp;quot;,
you may want to take a look at Gleam. It is a relatively young language that runs on top of the BEAM platform, which means
it can be added as an enhancement to an Elixir codebase without you having to rewrite everything.&lt;/p&gt;
&lt;p&gt;In this article, we will add Gleam code to an Elixir project.&lt;/p&gt;
&lt;h2&gt;Why Use Gleam for Elixir?&lt;/h2&gt;
&lt;p&gt;First, let&amp;#39;s ask ourselves a question: why would we use &lt;a href=&quot;https://gleam.io/&quot;&gt;Gleam&lt;/a&gt;? The Elixir ecosystem is mature at this point, with
a multitude of great solutions for everyday problems. Ecto and Phoenix make a really powerful
combination for writing web applications. Elixir itself is a dynamically typed language, which is great for some
applications but opens the door to a whole class of errors.&lt;/p&gt;
&lt;p&gt;Imagine you&amp;#39;re working on a critical payment processing system in Elixir and need to ensure your core logic&amp;#39;s absolute reliability
and correctness. Despite Elixir&amp;#39;s strengths, its dynamic typing sometimes leaves room for subtle
bugs. Enter Gleam. It&amp;#39;s a statically typed language for the BEAM platform that promises to enhance your system&amp;#39;s
robustness. Where Elixir falls a bit short, Gleam can shine. Let&amp;#39;s explore how to integrate Gleam with an Elixir project,
so we can have the best from both languages.&lt;/p&gt;
&lt;p&gt;We want our core business logic to be written in Gleam while the surrounding code is in Elixir (somewhat akin to the idea of a &amp;quot;functional core, imperative shell&amp;quot;, although in the functional world, it&amp;#39;s
rather a &amp;quot;pure core, stateful shell&amp;quot;). We will take this idea very far, establishing a physical boundary between the two
worlds.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see how to get there.&lt;/p&gt;
&lt;h2&gt;About The Project&lt;/h2&gt;
&lt;p&gt;To witness the power of Gleam in action, we will implement a feature in a made-up application to manage students at
a university. We will take care of their enrollment in courses. Our business rules will look as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A student can be enrolled in a course.&lt;/li&gt;
&lt;li&gt;Every course has a limited number of seats and a finite-length waitlist. If a student tries to enroll but all the
seats are already taken, they are put on the waitlist (if there are spots there; if not — the enrollment is rejected).&lt;/li&gt;
&lt;li&gt;If someone with a reserved seat cancels their enrollment, the first person on the waitlist takes their place.&lt;/li&gt;
&lt;li&gt;Some courses have age limits: only students older than a certain age can enroll.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will start the implementation by creating a fairly standard Phoenix and Ecto application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix phx.new student_roll
mix ecto.create
mix phx.gen.live Enrollment Student students name:string date_of_birth:date
mix phx.gen.live Enrollment Course courses name:string max_students:integer waitlist_size:integer min_age:integer
mix phx.gen.schema Enrollment.Enrollment enrollments student_id:integer course_id:integer waitlisted_at:datetime
mix ecto.migrate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this basic structure in place, we can add Gleam into the mix using the
&lt;a href=&quot;https://github.com/gleam-lang/mix_gleam&quot;&gt;&lt;code&gt;mix_gleam&lt;/code&gt;&lt;/a&gt; library. We will follow the steps from the
project README. First, install &lt;code&gt;mix_gleam&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix archive.install hex mix_gleam
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now prepare the project to use Gleam by adding some entries to &lt;code&gt;mix.exs&lt;/code&gt;&amp;#39;s project definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@app_name :student_roll

def project do
  [
    archives: [mix_gleam: &amp;quot;~&amp;gt; 0.6&amp;quot;],
    app: @app_name,
    compilers: [:gleam | Mix.compilers()],
    aliases: [
      &amp;quot;deps.get&amp;quot;: [&amp;quot;deps.get&amp;quot;, &amp;quot;gleam.deps.get&amp;quot;]
    ],
    erlc_paths: [
      &amp;quot;build/dev/erlang/#{@app_name}/_gleam_artefacts&amp;quot;
    ],
    erlc_include_path: &amp;quot;build/dev/erlang/#{@app_name}/include&amp;quot;,
    prune_code_paths: false,
    # rest of the function
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this assumes you are changing an existing &lt;code&gt;mix.exs&lt;/code&gt; file generated by &lt;code&gt;phx.new&lt;/code&gt;. These are required steps
to make the Gleam code work with Elixir, as outlined in the documentation. You don&amp;#39;t need to understand every single
change here (I, for instance, don&amp;#39;t). The important thing is &lt;code&gt;erlc_path&lt;/code&gt; which tells the compiler where to find compiled
Gleam files, so we can use them in our project.&lt;/p&gt;
&lt;p&gt;Next, also in &lt;code&gt;mix.exs&lt;/code&gt;, we need to add the Gleam standard library and testing framework to our dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    # others
    {:gleam_stdlib, &amp;quot;&amp;gt; 1.0&amp;quot;},
    {:gleeunit, &amp;quot;~&amp;gt; 1.0&amp;quot;, only: [:dev, :test], runtime: false}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, fetch dependencies and create the &lt;code&gt;src&lt;/code&gt; directory where the Gleam code will live:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.get
mkdir src
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Let&amp;#39;s Write Some Gleam&lt;/h2&gt;
&lt;p&gt;With all the setup in place, we can now start writing our business logic in Gleam! In the first iteration, we
will skip the waitlist functionality, but we will still create a system that checks if enrollment is possible. Let&amp;#39;s start
with a &lt;code&gt;src/enrollment.gleam&lt;/code&gt; file. &lt;code&gt;src&lt;/code&gt; is the directory at the top level of the project, where &lt;code&gt;mix_gleam&lt;/code&gt; expects
you to keep your Gleam code.&lt;/p&gt;
&lt;p&gt;We will put the following code in the file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub type Student {
  Student(id: Int, age: Int)
}

pub type Course {
  Course(id: Int, min_age: Int, seats: Int, seats_used: Int)
}

pub type RejectionReason {
  NoSeats
  AgeRequirementNotMet
}

pub type EnrollmentDecision {
  Enrolled
  Rejected(reason: RejectionReason)
}

pub fn enroll(student: Student, course: Course) -&amp;gt; EnrollmentDecision {
  case student.age &amp;gt;= course.min_age {
    False -&amp;gt; Rejected(AgeRequirementNotMet)
    True -&amp;gt;
      case course.seats &amp;gt; course.seats_used {
        False -&amp;gt; Rejected(NoSeats)
        True -&amp;gt; Enrolled
      }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are quite a few things to unpack here, so let&amp;#39;s take a quick crash course on Gleam.&lt;/p&gt;
&lt;h3&gt;What&amp;#39;s Happening Here?&lt;/h3&gt;
&lt;p&gt;In the first part, we define a bunch of types. Types are the heart of typed languages. Here we need a &lt;code&gt;Student&lt;/code&gt;,
a &lt;code&gt;Course&lt;/code&gt;, an &lt;code&gt;EnrollmentDecision&lt;/code&gt;, and a &lt;code&gt;RejectionReason&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Taking a &lt;code&gt;Student&lt;/code&gt; declaration, we define not only a type itself but also its &lt;strong&gt;constructor&lt;/strong&gt;, a &lt;code&gt;Student&lt;/code&gt;
with two arguments: &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;age&lt;/code&gt;. You can note that we don&amp;#39;t include the &lt;code&gt;name&lt;/code&gt; here, even though we defined it
before in the Elixir schema definition. The name is just side-data. We don&amp;#39;t use it for anything related to
business logic (unless you have a requirement, such as that only people with names starting
with E can take a course).&lt;/p&gt;
&lt;p&gt;A type like &lt;code&gt;RejectionReason&lt;/code&gt; defines two constructors, which we can basically read as no seats left or the age requirement not being met.&lt;/p&gt;
&lt;p&gt;At the end of the code block, we define an actual &lt;code&gt;enroll&lt;/code&gt; function. It takes a student and a course, and using
a &lt;code&gt;case&lt;/code&gt; statement, makes some decisions about the pending enrollment command. &lt;code&gt;case&lt;/code&gt; is the only flow control
structure in Gleam (there is no &lt;code&gt;if&lt;/code&gt;, for example). In this example, we first check the age requirement, and if it&amp;#39;s met,
we check if seats are left.&lt;/p&gt;
&lt;p&gt;With that code ready, we can now write a failing unit test. Let&amp;#39;s add a &lt;code&gt;student_roll_test.gleam&lt;/code&gt; file
in the &lt;code&gt;test&lt;/code&gt; directory (this is a naming convention that &lt;code&gt;mix_gleam&lt;/code&gt; expects). In that file, add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import enrollment.{Course, Enrolled, Student}
import gleeunit

pub fn main() {
  gleeunit.main()
}

pub fn enrolled_test() {
  let course = Course(id: 1, min_age: 21, seats: 10, seats_used: 9)
  let student = Student(id: 10, age: 20)
  let assert Enrolled = enrollment.enroll(student, course)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;#39;s a bit of boilerplate here, but in essence, we create a test function that builds a course with &lt;code&gt;id = 1&lt;/code&gt;,
&lt;code&gt;min_age = 21&lt;/code&gt;, &lt;code&gt;seats_limit = 10&lt;/code&gt; and &lt;code&gt;seats_taken = 9&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, we create a student who is 20 years old
(therefore too young to enroll). Finally, we try to enroll them. On running &lt;code&gt;mix gleam.test&lt;/code&gt;, you get the error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Running student_roll_test.main
F
Failures:

  1) enrollment_test.enrolled_test: module &amp;#39;enrollment_test&amp;#39;
     #{function =&amp;gt; &amp;lt;&amp;lt;&amp;quot;enrolled_test&amp;quot;&amp;gt;&amp;gt;,line =&amp;gt; 12,
       message =&amp;gt; &amp;lt;&amp;lt;&amp;quot;Assertion pattern match failed&amp;quot;&amp;gt;&amp;gt;,
       module =&amp;gt; &amp;lt;&amp;lt;&amp;quot;enrollment_test&amp;quot;&amp;gt;&amp;gt;,
       value =&amp;gt; {rejected,age_requirement_not_met},
       gleam_error =&amp;gt; let_assert}
     location: enrollment_test.enrolled_test:12
     stacktrace:
       enrollment_test.enrolled_test
     output:

Finished in 0.011 seconds
1 tests, 1 failures
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is good, but not great. Let&amp;#39;s improve the output by using &lt;code&gt;gleeunit/should&lt;/code&gt;, a library that makes the
unit testing experience better in Gleam:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import enrollment.{Course, Enrolled, Student}
import gleeunit
import gleeunit/should

pub fn main() {
  gleeunit.main()
}

pub fn enrolled_test() {
  let course = Course(id: 1, min_age: 21, seats: 10, seats_used: 9)
  let student = Student(id: 10, age: 20)
  enrollment.enroll(student, course)
  |&amp;gt; should.equal(Enrolled)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Now, the output is much more readable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Running student_roll_test.main
F
Failures:

  1) student_roll_test.enrolled_test: module &amp;#39;student_roll_test&amp;#39;
     Values were not equal
     expected: Enrolled
          got: Rejected(AgeRequirementNotMet)
     output:

Finished in 0.011 seconds
1 tests, 1 failures
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&amp;#39;s fix the test by calling it using a student who is old enough, and we will have a pass:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Running student_roll_test.main
.
Finished in 0.012 seconds
1 tests, 0 failures
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have the first test figured out, we should write some more tests to cover interesting branches in
the code. But one important question still lingers: &lt;strong&gt;How do I call this from my Phoenix project?&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Calling Gleam from Elixir&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s start working on the Phoenix side of our project. Go to &lt;code&gt;lib/student_roll/enrollment.ex&lt;/code&gt; and define two
functions related to the enrollment process:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def enrolled?(course_id, student_id) do
  from(e in Enrollment, where: e.student_id == ^student_id
    and e.course_id == ^course_id and is_nil(e.waitlisted_at))
  |&amp;gt; Repo.exists?()
end

def enroll(course_id, student_id) do
  student = get_student!(student_id)
  course = get_course!(course_id)

  # some logic should go here

  %Enrollment{}
  |&amp;gt; Enrollment.changeset(%{student_id: student.id, course_id: course.id})
  |&amp;gt; Repo.insert()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will write a test checking the enrollment logic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;describe &amp;quot;enrollment&amp;quot; do
  import StudentRoll.EnrollmentFixtures

  test &amp;quot;enroll a student&amp;quot; do
    birthday = DateTime.utc_now() |&amp;gt; DateTime.add(-18 * 365, :day)
    student = student_fixture(%{date_of_birth: birthday})
    course = course_fixture(%{min_age: 22})

    assert {:ok, _} = Enrollment.enroll(course.id, student.id)
    assert Enrollment.enrolled?(course.id, student.id)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it passes! But it should not. We created a student who is roughly 18 years old, but the course requires that the
students be at least 22. This is because we did not plug our Gleam-written business logic into the mix. Let&amp;#39;s fix this now.&lt;/p&gt;
&lt;p&gt;Calling compiled Gleam modules looks to Elixir the same way as Erlang modules. You invoke modules by prepending &lt;code&gt;:&lt;/code&gt;
to the module name. In our case, this will be &lt;code&gt;:enrollment&lt;/code&gt;. We will also have to pass something that Gleam can interpret as its &lt;code&gt;Student&lt;/code&gt; and &lt;code&gt;Course&lt;/code&gt; types. This is the boilerplate I mentioned earlier.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def enroll(course_id, student_id) do
  student = get_student!(student_id)
  course = get_course!(course_id)

  student_age =
    DateTime.utc_now() |&amp;gt; DateTime.to_date() |&amp;gt; Date.diff(student.date_of_birth) |&amp;gt; div(365)

  seats_taken =
    Repo.aggregate(
      from(e in Enrollment, where: e.course_id == ^course_id and is_nil(e.waitlisted_at)),
      :count
    )

  case :enrollment.enroll(
        {:student, student.id, student_age},
        {:course, course.id, course.min_age, course.max_students, seats_taken}
      ) do
    :enrolled -&amp;gt;
      %Enrollment{}
      |&amp;gt; Enrollment.changeset(%{student_id: student.id, course_id: course.id})
      |&amp;gt; Repo.insert()

    {:rejected, reason} -&amp;gt;
      {:error, reason}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our &lt;code&gt;enroll&lt;/code&gt; function is slightly inflated, so let&amp;#39;s walk through it.&lt;/p&gt;
&lt;p&gt;First, we need some more data. We calculate the student age in Elixir here and also fetch the number of already enrolled
students. Second, we build a structure that Gleam will interpret as its type. These are just tuples, where the
first element is the name of a type, followed by several fields required by the constructor.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Gleam: Student(id: Int, age: Int)
{:student, student.id, student_age}

# Gleam: Course(id: Int, min_age: Int, seats: Int, seats_used: Int)
{:course, course.id, course.min_age, course.max_students, seats_taken}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we call &lt;code&gt;:enrollment.enroll&lt;/code&gt; with these tuples. If we run the test now, we will get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;1) test enrollment enroll a student (StudentRoll.EnrollmentTest)
  test/student_roll/enrollment_test.exs:131
  match (=) failed
  code:  assert {:ok, _} = Enrollment.enroll(course.id, student.id)
  left:  {:ok, _}
  right: {:error, {:rejected, :age_requirement_not_met}}
  stacktrace:
    test/student_roll/enrollment_test.exs:136: (test)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is exactly what we wanted to have! The test does not pass because the student is too young.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub type RejectionReason {
  NoSeats
  AgeRequirementNotMet
}

pub type EnrollmentDecision {
  Enrolled
  Rejected(reason: RejectionReason)
}


# in Elixir:
# :enrolled | {:rejected, :age_requirement_not_met} | {:rejected | :no_seats}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ve made the first step. We called the Gleam code from Elixir, got the results back, and interpreted them back into Elixir
idioms (a result tuple of &lt;code&gt;{:ok, term()} | {:error, term()}&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;We should now write any remaining tests we want to run in Elixir. Remember that at this point,
the enrollment process is thoroughly unit tested in Gleam by Gleeunit, so perhaps we don&amp;#39;t need to duplicate all
the cases — only the ones that have consequences in Elixir (but this is up to you and your testing strategy).&lt;/p&gt;
&lt;p&gt;After this, we can refactor the &lt;code&gt;enroll&lt;/code&gt; function to look nicer and more reader-friendly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp get_gleam_student!(id) do
  student = get_student!(id)
  student_age =
    DateTime.utc_now() |&amp;gt; DateTime.to_date() |&amp;gt; Date.diff(student.date_of_birth) |&amp;gt; div(365)
  {:student, id, student_age}
end

defp get_gleam_course!(id) do
  course = get_course!(id)
  seats_taken =
    Repo.aggregate(
      from(e in Enrollment, where: e.course_id == ^id and is_nil(e.waitlisted_at)),
      :count
    )
  {:course, course.id, course.min_age, course.max_students, seats_taken}
end

def enroll(course_id, student_id) do
  course = get_gleam_course!(course_id)
  student = get_gleam_student!(student_id)

  case :enrollment.enroll(student, course) do
    :enrolled -&amp;gt;
      %Enrollment{}
      |&amp;gt; Enrollment.changeset(%{student_id: student_id, course_id: course_id})
      |&amp;gt; Repo.insert()

    {:rejected, reason} -&amp;gt;
      {:error, reason}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks better. You could even hide &lt;code&gt;get_gleam_student!/1&lt;/code&gt; and &lt;code&gt;get_gleam_course!/1&lt;/code&gt; in a module called,
for example, &lt;code&gt;GleamTypes&lt;/code&gt;. This way, other contexts that potentially call these structures in Gleam will have them readily
available.&lt;/p&gt;
&lt;p&gt;But that&amp;#39;s not all. We still have some work to do.&lt;/p&gt;
&lt;h2&gt;Implementing the Waitlist&lt;/h2&gt;
&lt;p&gt;If you recall, our initial requirements also included a waitlist.&lt;/p&gt;
&lt;p&gt;This is missing in the implementation above; now is the time to fix it. This will allow you to see how
changing the code in both Gleam and Elixir works. I strongly recommend you change the logic in Gleam first,
unit-test it, and only then, write the Elixir proxy code (although if you fancy some strict TDD, you can start with
some red Elixir tests too).&lt;/p&gt;
&lt;p&gt;But before diving into the code, let&amp;#39;s ask ourselves one design question: How should we represent the waitlist?
Should it be a number (&lt;code&gt;waitlist_size&lt;/code&gt;) or maybe a list of students? This is &lt;em&gt;the&lt;/em&gt; classic question in functional design
and probably deserves a separate article to address it fully.&lt;/p&gt;
&lt;p&gt;In our project, for already-signed-in students, we just pass a number of them, not a list of them. This time, we will model the waitlist as an actual list to make things more interesting.&lt;/p&gt;
&lt;p&gt;First, we need to change our domain model by extending the &lt;code&gt;Course&lt;/code&gt; type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub type Course {
  Course(
    id: Int,
    min_age: Int,
    seats: Int,
    seats_used: Int,
    waitlist: List(Student),
    max_waitlist_size: Int,
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then the list of enrollment decisions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub type EnrollmentDecision {
  Enrolled
  Rejected(reason: RejectionReason)
  Waitlisted
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, we have to adjust our existing Gleam tests because now they fail with the following message:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;error: Incorrect arity
   ┌─ /home/user/dev/student_roll/_build/dev/lib/student_roll/test/student_roll_test.gleam:10:16
   │
10 │   let course = Course(id: 1, min_age: 21, seats: 10, seats_used: 9)
   │                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Expected 6 arguments, got 4

This call accepts these additional labelled arguments:

  - max_waitlist_size
  - waitlist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we also have to modify the Elixir glue code that calls Gleam:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp get_gleam_student!(id) do
  get_student!(id)
  |&amp;gt; to_gleam_student()
end

defp to_gleam_student(student) do
  student_age =
    DateTime.utc_now() |&amp;gt; DateTime.to_date() |&amp;gt; Date.diff(student.date_of_birth) |&amp;gt; div(365)

  {:student, student.id, student_age}
end

defp get_gleam_course!(id) do
  course = get_course!(id)

  seats_taken =
    Repo.aggregate(
      from(e in Enrollment, where: e.course_id == ^id and is_nil(e.waitlisted_at)),
      :count
    )

  waitlist =
    from(e in Enrollment, where: e.course_id == ^id and not is_nil(e.waitlisted_at))
    |&amp;gt; Repo.all()
    |&amp;gt; Enum.map(&amp;amp;to_gleam_student/1)

  {:course, course.id, course.min_age, course.max_students, seats_taken, waitlist,
    course.waitlist_size}
end

# the enroll/2 function stays the same
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s write a failing test in Gleeunit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn waitlist_exceeded_test() {
  let course =
    Course(
      id: 2,
      min_age: 0,
      seats: 10,
      seats_used: 10,
      max_waitlist_size: 2,
      waitlist: [
        Student(id: 1, age: 22),
        Student(id: 2, age: 13),
        Student(id: 3, age: 54),
      ],
    )

  let student = Student(id: 4, age: 22)

  enrollment.enroll(student, course)
  |&amp;gt; should.equal(Rejected(NoSeats))
}

pub fn waitlisted_test() {
  let course =
    Course(
      id: 2,
      min_age: 0,
      seats: 10,
      seats_used: 10,
      max_waitlist_size: 2,
      waitlist: [],
    )

  let student = Student(id: 4, age: 22)

  enrollment.enroll(student, course)
  |&amp;gt; should.equal(Waitlisted)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of these tests will accidentally pass (because we reused the &lt;code&gt;NoSeats&lt;/code&gt; rejection reason, which might be a dubious choice).
But the other one fails. Let&amp;#39;s fix it now by actually implementing the waitlist. We need to import the &lt;code&gt;gleam/list&lt;/code&gt;
package on top and change the branch which previously resulted in &lt;code&gt;NoSeats&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;import gleam/list

# ...

pub fn enroll(student: Student, course: Course) -&amp;gt; EnrollmentDecision {
  case student.age &amp;gt;= course.min_age {
    False -&amp;gt; Rejected(AgeRequirementNotMet)
    True -&amp;gt;
      case course.seats &amp;gt; course.seats_used {
        False -&amp;gt;
          case list.length(course.waitlist) &amp;gt;= course.max_waitlist_size {
            True -&amp;gt; Rejected(NoSeats)
            False -&amp;gt; Waitlisted
          }
        True -&amp;gt; Enrolled
      }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final part will be done in Elixir. We have decided that a person should go to the waitlist, but now we have
to persist it. Again, let&amp;#39;s start with a test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;waitlist a student&amp;quot; do
  student1 = student_fixture()
  student2 = student_fixture()
  course = course_fixture(%{max_students: 1, waitlist_size: 10})
  Enrollment.enroll(course.id, student1.id)
  Enrollment.enroll(course.id, student2.id)
  assert Enrollment.waitlisted?(course.id, student2.id)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need the &lt;code&gt;waitlisted?&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def waitlisted?(course_id, student_id) do
  from(e in Enrollment,
    where:
      e.student_id == ^student_id and
        e.course_id == ^course_id and not is_nil(e.waitlisted_at)
  )
  |&amp;gt; Repo.exists?()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we implement the infrastructure part, persisting the waitlist in the database. In the
&lt;code&gt;enroll&lt;/code&gt; function&amp;#39;s &lt;code&gt;case&lt;/code&gt; statement, we need to handle the &lt;code&gt;:waitlisted&lt;/code&gt; return type case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;:waitlisted -&amp;gt;
  %Enrollment{}
  |&amp;gt; Enrollment.changeset(%{student_id: student_id, course_id: course_id, waitlisted_at: DateTime.utc_now()})
  |&amp;gt; Repo.insert()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All the tests pass now. We have, therefore, successfully implemented a waitlist function in our Gleam/Elixir application!&lt;/p&gt;
&lt;p&gt;Looking at the requirements, we still have some way to go. We haven&amp;#39;t touched on canceling an enrollment (when a user
has successfully enrolled in the past but is no longer interested). Hint: this handles moving a person from a waitlist
to a regular enrollment, so we at least need this type as a return value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub type CancellingEnrollmentDecision {
  Cancelled
  CancelledWithWaitlistProcessed(Student)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;#39;s also a big topic that can be explored further but was not even covered in our requirements: how we should handle uniqueness. Everyone
should be able to enroll in a given course only once, and they should not be able to cancel if they are not enrolled.
There are at least three ways to model that behavior between Gleam and Elixir, but that&amp;#39;s a topic for a separate article.&lt;/p&gt;
&lt;h2&gt;Why Did We Do It Again?&lt;/h2&gt;
&lt;p&gt;Everything we&amp;#39;ve done here could, of course, all have been written just in Elixir. The code would be shorter and in one language. In most cases,
splitting the responsibilities between Elixir and Gleam probably would be a questionable choice. However, I personally
think it&amp;#39;s something worth considering if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You like to model your application with types and are missing this from Elixir.&lt;/li&gt;
&lt;li&gt;You expect your business logic to grow in complexity and want guarantees from a statically typed language
to help you manage that complexity.&lt;/li&gt;
&lt;li&gt;You want a strong separation between pure business logic and stateful application code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these are true for you, consider this arcane-looking setup. In any case, it&amp;#39;s good to be
aware that it is possible.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;I have shown you how to call Gleam from an Elixir application and how to interpret the results. We wrote tests in both
languages and some glue code.&lt;/p&gt;
&lt;p&gt;Happy coding, whether you choose to do it only in Elixir or you also make use of Gleam!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Track Errors in Phoenix for Elixir with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/07/09/track-errors-in-phoenix-for-elixir-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2024/07/09/track-errors-in-phoenix-for-elixir-with-appsignal.html</id>
    <published>2024-07-09T00:00:00+00:00</published>
    <updated>2024-07-09T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first part of this two-part series, we&#039;ll integrate AppSignal into an Elixir application and track errors.</summary>
    <content type="html">&lt;p&gt;AppSignal is a powerful error tracking and performance monitoring tool that can help you maintain reliability and speed in your Elixir applications.&lt;/p&gt;
&lt;p&gt;In this tutorial, the first of a two-part series, you&amp;#39;ll learn how to integrate AppSignal into your Elixir application, configure it for error tracking, interpret error reports, and leverage AppSignal&amp;#39;s features to debug and resolve issues.&lt;/p&gt;
&lt;p&gt;Whether you&amp;#39;re a seasoned Elixir developer looking to improve your application&amp;#39;s error handling or a beginner who wants to understand how error tracking works, this step-by-step tutorial will give you a firm foundation for using AppSignal to track errors in your Elixir app.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow along with this tutorial, you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Elixir development environment. If you don&amp;#39;t have Elixir installed, follow the steps in &lt;a href=&quot;https://elixir-lang.org/install.html&quot;&gt;this guide&lt;/a&gt; for your operating system.&lt;/li&gt;
&lt;li&gt;An existing Elixir app. If you don&amp;#39;t have one, go ahead and &lt;a href=&quot;https://github.com/iamaestimo/game_reviews_liveview&quot;&gt;fork this app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Some experience working with Elixir/Phoenix.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Integrating AppSignal Into a Phoenix App&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Quick tip: As of writing this article, AppSignal currently supports pure Elixir, Plug, and Phoenix apps. The examples used for this tutorial are centered around a Phoenix app featuring video games, users, and reviews, but the steps taken should be relatively similar for the other supported flavors.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;AppSignal provides excellent support for the &lt;a href=&quot;https://www.appsignal.com/elixir/phoenix-monitoring&quot;&gt;Phoenix framework&lt;/a&gt; and the installation process is very seamless. First, &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;sign up for a free 30-day trial&lt;/a&gt;, no card details required.&lt;/p&gt;
&lt;p&gt;Then open the Phoenix app&amp;#39;s dependencies file and add AppSignal&amp;#39;s Phoenix package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs

...
defp deps do
  [
    ...
    {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
  ]
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;mix deps.get&lt;/code&gt; to add the package to your app. Once it&amp;#39;s added successfully, install it by running the command below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix appsignal.install &amp;lt;PUSH_API_KEY&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: You can get your PUSH_API_KEY from the AppSignal dashboard.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When you run this command, you&amp;#39;ll be presented with some options to customize the installation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Validating Push API key: Valid! 🎉
What is your application&amp;#39;s name? [game_reviews_app]: &amp;lt;APP NAME&amp;gt;

There are two methods of configuring AppSignal in your application.
  Option 1: Using a &amp;quot;config/appsignal.exs&amp;quot; file. (1)
  Option 2: Using system environment variables.  (2)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The first option is your app&amp;#39;s name as you want it to appear on the AppSignal dashboard.&lt;/li&gt;
&lt;li&gt;The second option is how to configure AppSignal: via a configuration file or a system variable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Configuring AppSignal&lt;/h2&gt;
&lt;p&gt;For your app to send data to AppSignal, you should have a minimal configuration in &lt;code&gt;config/appsignal.exs&lt;/code&gt;, as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/appsignal.exs

import Config

config :appsignal, :config,
  otp_app: :game_reviews_app,
  name: &amp;quot;Phoenix API app&amp;quot;,
  push_api_key: &amp;lt;AppSignal Push API key&amp;gt;,
  env: Mix.env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or you can set this up using system environment variables. One thing to note is that this file can be configured to your liking using a &lt;a href=&quot;https://docs.appsignal.com/elixir/configuration/options.html&quot;&gt;variety of options&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Assuming the configuration proceeds without a hitch, you should now see your app automatically added to the AppSignal dashboard, as shown below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/phoenix-app-added-to-appsignal.png&quot; alt=&quot;Phoenix app added to AppSignal&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: It may take a couple of minutes for your app&amp;#39;s data to start showing.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Great, now let&amp;#39;s see how we can instrument an error in AppSignal.&lt;/p&gt;
&lt;h2&gt;Instrumenting Elixir Errors&lt;/h2&gt;
&lt;p&gt;This example app is a simple Phoenix LiveView app featuring a video game and reviews.&lt;/p&gt;
&lt;p&gt;Once you&amp;#39;ve &lt;a href=&quot;https://github.com/iamaestimo/game_reviews_liveview&quot;&gt;cloned the application&lt;/a&gt; to your development environment, run &lt;code&gt;mix deps.get&lt;/code&gt; to install all the dependencies, then you can run the app with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix phx.server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will make the app available on &lt;code&gt;http://localhost:4000&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Go ahead and test it by creating a few games with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;curl --location --request POST &amp;#39;http://localhost:4000/api/games&amp;#39; \
--header &amp;#39;Content-Type: application/json&amp;#39; \
--header &amp;#39;Accept: */*&amp;#39; \
--header &amp;#39;Host: localhost:4000&amp;#39; \
--header &amp;#39;Connection: keep-alive&amp;#39; \
--data-raw &amp;#39;{
    &amp;quot;game&amp;quot;: {
        &amp;quot;title&amp;quot;: &amp;quot;Hell divers&amp;quot;,
        &amp;quot;genre&amp;quot;: &amp;quot;Action&amp;quot;,
        &amp;quot;publisher&amp;quot;: &amp;quot;Arrowhead Studios&amp;quot;
    }
}&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having made a couple of games this way, you can now make a GET request for the games list (I use Insomnia for this, but you can use whatever you like):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/testing-the-api-app.png&quot; alt=&quot;Requesting the games list&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Which should execute successfully, as you can see above.&lt;/p&gt;
&lt;p&gt;Now, let&amp;#39;s deliberately cause an error to see how it will be shown on the AppSignal dashboard.&lt;/p&gt;
&lt;p&gt;Firstly, create a function defining a custom exception:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/exceptions/plug_exception.ex

defmodule GameReviewsApp.PlugException do
  defexception [:plug_status, message: &amp;quot;&amp;quot;]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, modify the index action in the games controller to call this function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GameReviewsAppWeb.GameController do
  ...
  def index(conn, _params) do
    raise GameReviewsApp.PlugException, plug_status: 403, message: &amp;quot;You&amp;#39;re not allowed!&amp;quot;
    games = Games.list_games()
    render(conn, :index, games: games)
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when we make a request to the games list, this custom exception is raised:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/custom-exception.png&quot; alt=&quot;Custom exception&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And the same is shown on the AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/custom-exception-on-appsignal.png&quot; alt=&quot;Custom exception on AppSignal&quot;/&gt;&lt;/p&gt;
&lt;p&gt;If you click on the displayed error link, AppSignal gives you more context on the error, which should help you resolve it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/error-details.png&quot; alt=&quot;Error details&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Next up, let&amp;#39;s learn how we can track Ecto queries inside AppSignal.&lt;/p&gt;
&lt;h2&gt;Instrumenting Ecto queries in AppSignal&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.html&quot;&gt;Ecto&lt;/a&gt; is the most popular database abstraction library for Elixir apps.&lt;/p&gt;
&lt;p&gt;AppSignal provides native support for Ecto by hooking into the Ecto query telemetry layer, giving you query profiling, identification of slow queries, and more, with no extra work on your part (as long as the &lt;code&gt;otp_app&lt;/code&gt; name within the AppSignal configuration file matches the name of your app in &lt;code&gt;config.exs&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/config.exs

...
# General application configuration
import Config

config :game_reviews_app,
...
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/appsignal.exs

import Config

config :appsignal, :config,
  otp_app: :game_reviews_app,
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With our configuration done, AppSignal&amp;#39;s instrumentation will now automatically pick up Ecto queries and display them on this dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/default-ecto-instrumentation.png&quot; alt=&quot;Default Ecto instrumentation&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now this might be good enough for normal Ecto queries. But to pick up query types such as preloads in the right way, you&amp;#39;ll need to edit your app&amp;#39;s repo:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app/repo.ex

defmodule PhxRestApiApp.Repo do
  # use Ecto.Repo,       #...replace this default line with the one below...
  use Appsignal.Ecto.Repo,
    otp_app: :game_reviews_app,
    adapter: Ecto.Adapters.SQLite3
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let&amp;#39;s learn how to track Phoenix LiveViews using AppSignal.&lt;/p&gt;
&lt;h2&gt;Instrument Phoenix LiveView with AppSignal&lt;/h2&gt;
&lt;p&gt;With the latest AppSignal for Elixir package (version 2.12.0 as of writing), you can instrument LiveView dashboards in AppSignal.&lt;/p&gt;
&lt;p&gt;Simply adding the package is enough to automatically add your app&amp;#39;s live views using the AppSignal package&amp;#39;s telemetry handlers. Or you can configure the instrumentation manually using helpers made available by the package.&lt;/p&gt;
&lt;p&gt;The code below shows how easy it is to manually configure LiveView instrumentation by adding a single line within &lt;code&gt;application.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/game_reviews_app/application.ex

...
def start(_type, _args) do
  Appsignal.Phoenix.LiveView.attach() # &amp;lt;= ...added this line

  children = [
    ...
  ]
  ...
end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that, you&amp;#39;re able to view LiveView &lt;code&gt;mount&lt;/code&gt;, &lt;code&gt;handle_event&lt;/code&gt;, and &lt;code&gt;handle_param&lt;/code&gt; events in the AppSignal dashboard, like so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/liveview-instrumentation-1.png&quot; alt=&quot;Liveview instrumentation - 1&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/liveview-instrumentation-2.png&quot; alt=&quot;Liveview instrumentation - 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/liveview-instrumentation-3.png&quot; alt=&quot;Liveview instrumentation - 3&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Additionally, with the AppSignal LiveView instrumentation helpers, you can wrap LiveView action definitions within an &lt;code&gt;instrument/3&lt;/code&gt; block for even more granular visualizations, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# live/welcome_live.ex

defmodule GameReviewsAppWeb.WelcomeLive do
  use GameReviewsAppWeb, :live_view

  import Appsignal.Phoenix.LiveView, only: [instrument: 4]

  def mount(_params, _session, socket) do
    instrument(__MODULE__, &amp;quot;timer instrumentation&amp;quot;, socket, fn -&amp;gt;
      :timer.send_interval(1000, self(), :tick)
      {
        :ok,
        assign(socket, current_time: DateTime.utc_now())
      }
    end)
  end

  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;
      &amp;lt;h1&amp;gt;Welcome to my LiveView App&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;Current time: &amp;lt;%= @current_time %&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When sending metrics to AppSignal, you can use &lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation/instrumentation.html&quot;&gt;a gauge, a counter, or a distribution&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the code above, we define a counter measurement called &amp;quot;timer instrumentation&amp;quot; to send current time measurements to the AppSignal dashboard continuously.&lt;/p&gt;
&lt;p&gt;As you can see below, by switching the dashboard view from &amp;quot;web&amp;quot; to &amp;quot;live_view&amp;quot;, &amp;quot;timer instrumentation&amp;quot; is now available on the dashboard as a sample (with all the details you need to dig further):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/instrument-3-in-action.png&quot; alt=&quot;Instrumenting an AppSignal counter in Elixir&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Finally, I&amp;#39;ll highlight a nifty feature that makes AppSignal really stand out in the application performance monitoring space: automated dashboards.&lt;/p&gt;
&lt;h2&gt;AppSignal&amp;#39;s Automated Dashboards for Elixir&lt;/h2&gt;
&lt;p&gt;Whenever you add AppSignal to an app built using Elixir, it automatically creates a dashboard.&lt;/p&gt;
&lt;p&gt;When we add the AppSignal package to the Phoenix app, we get an automated dashboard and notification — in this case, an Erlang Virtual Machine dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/automated-dashboard-notification.png&quot; alt=&quot;Automated dashboard creation notification&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/automated-dashboard-link.png&quot; alt=&quot;Automated dashboard link&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-07/automated-dashboard.png&quot; alt=&quot;Automated dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://docs.appsignal.com/elixir.html&quot;&gt;AppSignal for Elixir documentation&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we&amp;#39;ve seen how to track Ecto queries and Phoenix LiveViews using AppSignal for Elixir. Consider this an introduction to what is possible when it comes to error tracking in Elixir with AppSignal.&lt;/p&gt;
&lt;p&gt;Next time, we&amp;#39;ll deep dive into custom instrumentation using Phoenix and Ecto&amp;#39;s in-built telemetry features, learning how you can craft and send custom metrics to AppSignal for monitoring even more powerful use cases.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Leverage Concurrency Efficiently When Managing Multiple Tasks in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/06/25/leverage-concurrency-efficiently-when-managing-multiple-tasks-in-elixir.html"/>
    <id>https://blog.appsignal.com/2024/06/25/leverage-concurrency-efficiently-when-managing-multiple-tasks-in-elixir.html</id>
    <published>2024-06-25T00:00:00+00:00</published>
    <updated>2024-06-25T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s run Task processes in Elixir, including `Task.async_stream/3`, to manage multiple tasks concurrently.</summary>
    <content type="html">&lt;p&gt;When working on multiple tasks, it&amp;#39;s important to consider performing them concurrently. However, when using concurrency, we need to be careful not to overload our system resources.&lt;/p&gt;
&lt;p&gt;In this article, we will cover the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is concurrency?&lt;/li&gt;
&lt;li&gt;How can we use concurrency in Elixir?&lt;/li&gt;
&lt;li&gt;Common issues when working with a series of tasks concurrently.&lt;/li&gt;
&lt;li&gt;How to efficiently manage a series of tasks using the Task module.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;What is Concurrency?&lt;/h2&gt;
&lt;p&gt;Concurrency is the ability to execute multiple tasks at the same time.&lt;/p&gt;
&lt;p&gt;Concurrency and parallelism are crucial features in modern programming. The operating systems installed on our computers are designed to incorporate these features. Both concurrency and parallelism involve executing multiple tasks simultaneously. However, concurrency focuses on managing multiple tasks within one resource. This can be achieved through techniques like multitasking and asynchronous programming. In an operating system, concurrency can be achieved by opening multiple applications to perform different tasks at the same time, also referred to as multitasking.&lt;/p&gt;
&lt;p&gt;On the other hand, parallelism involves executing multiple tasks simultaneously across multiple processing units (such as multiple CPU cores or distributed computing resources), thus improving system speed.&lt;/p&gt;
&lt;h2&gt;How Can We Use Concurrency in Elixir?&lt;/h2&gt;
&lt;p&gt;To achieve concurrency in Elixir, you need to initiate a process and execute the function or code responsible for performing a specific task within that process.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of some basic Elixir code that we can take a look at.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def send_message(phone_number) do
  # Simulate some processing time
  Process.sleep(3000)
  IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
  {:ok, &amp;quot;sent&amp;quot;}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we&amp;#39;ve added a 3-second sleep to simulate the fact that sending a message to an external phone number can sometimes cause some latency.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;send_message/1&lt;/code&gt; is invoked, this function will delay processing for 3 seconds before printing a message. It will also return an &lt;code&gt;{:ok, &amp;quot;sent&amp;quot;}&lt;/code&gt; tuple to indicate that the message was successfully sent to the given phone number.&lt;/p&gt;
&lt;p&gt;When executing synchronous Elixir code like the code above, we must wait for it to complete before receiving the output. If we need to send messages to multiple phone numbers, each with a delay of 3 seconds, it could take a significant amount of time to receive a notification that all messages have been successfully sent.&lt;/p&gt;
&lt;h3&gt;Taking It One Step Further&lt;/h3&gt;
&lt;p&gt;Now, let&amp;#39;s take it a step further and write some code that sends a message to multiple phone numbers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def send_to_all(phone_numbers) do
  Enum.each(phone_numbers, &amp;amp;send_message/1)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;send_to_all/1&lt;/code&gt; function takes a list of phone numbers as an argument and uses the &lt;code&gt;Enum.each/2&lt;/code&gt; function to iterate over the list, sending a message to each phone number using the &lt;code&gt;send_message&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;If you run this function in &lt;code&gt;iex&lt;/code&gt;, you will notice two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It takes longer to receive the final output, which is an atom &lt;code&gt;:ok&lt;/code&gt;. &lt;code&gt;Enum.each/2&lt;/code&gt; returns &lt;code&gt;:ok&lt;/code&gt; when invoked.&lt;/li&gt;
&lt;li&gt;Printing happens one at a time, with each print taking 3 seconds. Depending on the number of phone numbers provided, &lt;code&gt;send_message/1&lt;/code&gt; is called 5 times in our case, taking about 15 seconds to complete.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This means that when sending a message to a given phone number, each phone number has to wait for the preceding phone number to execute before moving on to the next one. The execution is synchronous, also known as blocking code.&lt;/p&gt;
&lt;p&gt;Elixir provides the ability to run code concurrently or asynchronously. Asynchronous code allows you to execute multiple tasks simultaneously. This type of code is also referred to as non-blocking code because it does not hinder the primary execution of a program.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s improve the &lt;code&gt;send_to_all/1&lt;/code&gt; function by running the task of sending messages to each phone number asynchronously. We need to start a process for each task.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A &lt;code&gt;process&lt;/code&gt; is a separate entity where code execution occurs.&lt;/em&gt; These processes are lightweight, run concurrently, and are isolated from each other. The code we write runs inside processes. The IEx (interactive shell) is an example of an Elixir process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def send_to_all(phone_numbers) do
  Enum.each(phone_numbers, fn phone_number -&amp;gt;
    Task.start(fn -&amp;gt; send_message(phone_number) end)
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&amp;#39;ve used &lt;code&gt;Task.start/1&lt;/code&gt; (which we&amp;#39;ll go over in more detail later) to start a process for each task.
After we recompile and run this function again in our IEx, you will notice two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It runs faster than before because it&amp;#39;s now running asynchronously. The final output — &lt;code&gt;:ok&lt;/code&gt; — is immediately returned even before we see the printed success messages.&lt;/li&gt;
&lt;li&gt;It instantly prints the success message at once for all tasks, which means that all the messages are being sent at the same time.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Running Tasks Concurrently using the Task Module&lt;/h2&gt;
&lt;p&gt;Elixir has a standard library Task module commonly used for running code concurrently. This allows you to perform tasks asynchronously, which can lead to improved performance and responsiveness in your applications.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s go back to our &lt;code&gt;send_to_all/1&lt;/code&gt; function. At first, we used this function to send messages to multiple phone numbers sequentially.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Sequential version of send_to_all/1
def send_to_all(phone_numbers) do
  Enum.each(phone_numbers, fn phone_number -&amp;gt;
    Task.start(fn -&amp;gt; send_message(phone_number) end)
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the sequential version, &lt;code&gt;send_message/1&lt;/code&gt; was called for each message in the list, one after the other.&lt;/p&gt;
&lt;p&gt;Later on, we converted the sequential code into concurrent code using &lt;code&gt;Task.start/1&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Asynchronous version using Task.start/1
def send_to_all(phone_numbers) do
  Enum.each(phone_numbers, fn phone_number -&amp;gt;
    Task.start(fn -&amp;gt; send_message(phone_number) end)
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the asynchronous version, &lt;code&gt;Task.start/1&lt;/code&gt; creates a separate task for each message, allowing the tasks to execute concurrently.&lt;/p&gt;
&lt;p&gt;The Task module has several useful functions to run code concurrently. Let&amp;#39;s now look at a few of these functions.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;Task.start/1&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Task.start/1&lt;/code&gt; is used to start a new process/task. It takes in an anonymous function with zero arity as an argument, where the intended work is performed. Usually, it doesn&amp;#39;t return the result of the executed function. Instead, it returns an &lt;code&gt;{:ok, PID}&lt;/code&gt; tuple, where &lt;code&gt;:ok&lt;/code&gt; means the process was started successfully, and &lt;code&gt;PID&lt;/code&gt; stands for process identifier: a number that uniquely identifies an Elixir process.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s try it out in IEx:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; {:ok, pid} = Task.start(fn -&amp;gt;  IO.puts(&amp;quot;converting to asyncronous code&amp;quot;) end)
         converting to asyncronous code
          {:ok, #PID&amp;lt;0.153.0&amp;gt;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The message is printed instantly and the result is &lt;code&gt;{:ok, #PID&amp;lt;0.153.0&amp;gt;}&lt;/code&gt;. This means that the process was started successfully. &lt;code&gt;pid&lt;/code&gt; represents the process started by &lt;code&gt;Task.start/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, it&amp;#39;s hard to know if all the messages were sent successfully using &lt;code&gt;Task.start/1&lt;/code&gt;, since it will still return &lt;code&gt;{:ok, PID}&lt;/code&gt;, which stands for a process that&amp;#39;s started successfully.&lt;/p&gt;
&lt;p&gt;It is useful in cases where you don&amp;#39;t have interest in the returned result or whether it completes successfully.&lt;/p&gt;
&lt;p&gt;A good example is working on a background job processing system, such as sending messages to registered users every midnight. You can use &lt;code&gt;Task.start/1&lt;/code&gt; to asynchronously handle each task that sends messages to users. In this context, you&amp;#39;re not particularly interested in the return value of &lt;code&gt;Task.start/1&lt;/code&gt;, because your main concern is to handle the tasks asynchronously, and you have a mechanism to track the status of each task. This mechanism can involve saving the status in the database, ensuring that any pending tasks are retried in subsequent runs.&lt;/p&gt;
&lt;p&gt;In case something goes wrong when sending messages to users, the status of the message will still be pending in the database. You can guarantee that the worker will run again at midnight and retry for pending messages.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;Task.async/1&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Like &lt;code&gt;Task.start/1&lt;/code&gt;, &lt;code&gt;Task.async/1&lt;/code&gt; is also used to start a process. The difference between &lt;code&gt;Task.async/&lt;/code&gt; and &lt;code&gt;Task.start/&lt;/code&gt; is that with &lt;code&gt;Task.async/1&lt;/code&gt;, you can retrieve the function result executed within the process.
It takes in an anonymous function with zero arity which starts a process and then returns a &lt;code&gt;%Task{}&lt;/code&gt; struct.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s try it out in IEx:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Task.async(fn -&amp;gt; IO.puts(&amp;quot;converting to asyncronous code using async&amp;quot;) end)
    converting to asyncronous code using async
      %Task{
        mfa: {:erlang, :apply, 2},
        owner: #PID&amp;lt;0.109.0&amp;gt;,
        pid: #PID&amp;lt;0.110.0&amp;gt;,
        ref: #Reference&amp;lt;0.0.13955.2933390707.3162308609.257437&amp;gt;
      }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The message is printed immediately and returns a &lt;code&gt;%Task{}&lt;/code&gt; struct as the output. The returned Task struct includes useful information about the process that&amp;#39;s started:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;owner&lt;/code&gt; represents the Process Identifier (PID) of the process that started the Task. In our example, the owner is IEx since we are running code within the shell. If we run &lt;code&gt;self()&lt;/code&gt;, the function that returns the &lt;code&gt;PID&lt;/code&gt; of the current process, then the PID returned by &lt;code&gt;self()&lt;/code&gt; will indeed match the PID of the owner of the task started.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pid&lt;/code&gt;: The process identifier of the process started by the task. You can use this PID to monitor the process further if needed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ref&lt;/code&gt;: This is a process monitor reference that can be used in cases where you want to be notified about how and where a process exits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To retrieve a result from the returned task, use either &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/Task.html#await/2&quot;&gt;&lt;code&gt;Task.await/2&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/Task.html#yield/2&quot;&gt;&lt;code&gt;Task.yield/2&lt;/code&gt;&lt;/a&gt;. They both accept a &lt;code&gt;%Task{}&lt;/code&gt; struct as an argument and handle process timeout. However, they handle the timeout differently.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Task.await/2&lt;/code&gt; and &lt;code&gt;Task.yield/2&lt;/code&gt; have a default timeout of &lt;code&gt;5000ms&lt;/code&gt; or &lt;code&gt;5 seconds&lt;/code&gt; to ensure that processes don&amp;#39;t get stuck waiting for a result forever. &lt;code&gt;Task.await/2&lt;/code&gt; will cause an exception and crash the process if there is a slower task taking more than &lt;code&gt;5000ms&lt;/code&gt; to complete, while &lt;code&gt;Task.yield/2&lt;/code&gt; returns nil.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s modify &lt;code&gt;send_to_all/1&lt;/code&gt; to use &lt;code&gt;Task.async/1&lt;/code&gt;, then retrieve its result using &lt;code&gt;Task.await/2&lt;/code&gt;. Later, use &lt;code&gt;Task.yield/2&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def send_to_all(phone_numbers) do
  phone_numbers
  |&amp;gt; Enum.map(fn phone_number -&amp;gt;
    Task.async(fn -&amp;gt; send_message(phone_number) end)
  end)
  |&amp;gt; IO.inspect(label: &amp;quot;started tasks++++&amp;quot;)
  |&amp;gt; Enum.map(fn task -&amp;gt; Task.await(task) end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;send_to_all/1&lt;/code&gt; iterates over a given list of phone numbers using &lt;code&gt;Enum.map/2&lt;/code&gt; instead of &lt;code&gt;Enum.each/2&lt;/code&gt; to retrieve the result of each task, and spawns a task for each using &lt;code&gt;Task.async/1&lt;/code&gt;. Then we use &lt;code&gt;Task.await/2&lt;/code&gt; to retrieve the result of each task. It waits for the task to complete and then returns a result.&lt;/p&gt;
&lt;p&gt;Run the &lt;code&gt;send_to_all/1&lt;/code&gt; function in IEx:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; send_to_all(1..10)
started tasks++++[
  %Task{
    mfa: {:erlang, :apply, 2},
    owner: #PID&amp;lt;0.150.0&amp;gt;,
    pid: #PID&amp;lt;0.151.0&amp;gt;,
    ref: #Reference&amp;lt;0.0.19203.3913757788.1002242054.113465&amp;gt;
  },
  %Task{
    mfa: {:erlang, :apply, 2},
    owner: #PID&amp;lt;0.150.0&amp;gt;,
    pid: #PID&amp;lt;0.152.0&amp;gt;,
    ref: #Reference&amp;lt;0.0.19203.3913757788.1002242054.113469&amp;gt;
  },..
]

sending message  to 1
sending message  to 2
sending message  to 3
sending message  to 4
sending message  to 5
sending message  to 6
sending message  to 7
sending message  to 8
sending message  to 9
sending message  to 10

[
  {:ok, &amp;quot;sent&amp;quot;},
  {:ok, &amp;quot;sent&amp;quot;},
...
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at the inspected result, each task represents a spawned process. They all have a different &lt;code&gt;pid&lt;/code&gt; with a similar &lt;code&gt;owner&lt;/code&gt; pid meaning that the caller process (IEx) is one. Once each task is completed, the messages are printed at the same time and the result returned. The final result returned is a list of output expected from &lt;code&gt;send_message/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, let&amp;#39;s retrieve the result from each spawned task using &lt;code&gt;Task.yield/2&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def send_to_all(phone_numbers) do
  phone_numbers
  |&amp;gt; Enum.map(fn phone_number -&amp;gt;
    Task.async(fn -&amp;gt; send_message(phone_number) end)
  end)
  |&amp;gt; IO.inspect(label: &amp;quot;started tasks++++&amp;quot;)
  |&amp;gt; Enum.map(fn task -&amp;gt; Task.yield(task) end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; send_to_all(1..10)
started tasks++++[
  %Task{
    mfa: {:erlang, :apply, 2},
    owner: #PID&amp;lt;0.150.0&amp;gt;,
    pid: #PID&amp;lt;0.151.0&amp;gt;,
    ref: #Reference&amp;lt;0.0.19203.3913757788.1002242054.113465&amp;gt;
  },
  %Task{
    mfa: {:erlang, :apply, 2},
    owner: #PID&amp;lt;0.150.0&amp;gt;,
    pid: #PID&amp;lt;0.152.0&amp;gt;,
    ref: #Reference&amp;lt;0.0.19203.3913757788.1002242054.113469&amp;gt;
  },..
]

sending message  to 1
sending message  to 2
sending message  to 3
sending message  to 4
sending message  to 5
sending message  to 6
sending message  to 7
sending message  to 8
sending message  to 9
sending message  to 10

[
  :ok, {:ok, &amp;quot;sent&amp;quot;},
  :ok, {:ok, &amp;quot;sent&amp;quot;},
...
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result is similar. However, &lt;code&gt;Task.yield/2&lt;/code&gt; returns an &lt;code&gt;{:ok, term()}&lt;/code&gt; tuple, where &lt;code&gt;term&lt;/code&gt; represents the result returned by the function executed within the process. That&amp;#39;s why our output is a list of the &lt;code&gt;{:ok, {:ok, &amp;quot;sent&amp;quot;}}&lt;/code&gt; tuple where &lt;code&gt;{:ok, &amp;quot;sent&amp;quot;}&lt;/code&gt; is the expected result from &lt;code&gt;send_message/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In our &lt;code&gt;send_to_all/1&lt;/code&gt; function, we used &lt;code&gt;Task.start/2&lt;/code&gt; and &lt;code&gt;Task.async/2&lt;/code&gt; to start each task of sending a message to a given phone number in the background, allowing them to run concurrently. Starting a separate process for each task when sending a message ensures its isolation. Therefore, if one task encounters an error or fails for any reason, it won&amp;#39;t affect the execution of other tasks.&lt;/p&gt;
&lt;h3&gt;An Example with an Error&lt;/h3&gt;
&lt;p&gt;For example, let&amp;#39;s assume we have introduced an error in one of the tasks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def send_message(3) do
  # Simulate some processing time
  Process.sleep(3000)
  IO.puts(&amp;quot;Sending message to #{3 + &amp;quot;a&amp;quot;}&amp;quot;)
  {:ok, &amp;quot;sent&amp;quot;}
end

def send_message(phone_number) do
  # Simulate some processing time
  Process.sleep(3000)
  IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
  {:ok, &amp;quot;sent&amp;quot;}
end

# Asynchronous version using Task.start/1
def send_to_all(phone_numbers) do
  Enum.each(phone_numbers, fn phone_number -&amp;gt;
    Task.start(fn -&amp;gt; send_message(phone_number) end)
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the &lt;code&gt;send_message/1&lt;/code&gt; function has two function heads. The first function head pattern matches on 3 and deliberately raises an arithmetic error by adding the number 3 to a string &lt;code&gt;&amp;quot;a&amp;quot;&lt;/code&gt;. The second function head handles other &lt;code&gt;phone numbers&lt;/code&gt; values and simulates sending messages as before.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; send_to_all(1..5)
06:19:17.562 [error] Task #PID&amp;lt;0.294.0&amp;gt; started from #PID&amp;lt;0.291.0&amp;gt; terminating
** (ArithmeticError) bad argument in arithmetic expression
    :erlang.+(3, &amp;quot;a&amp;quot;)

[
  ok: #PID&amp;lt;0.292.0&amp;gt;,
  ok: #PID&amp;lt;0.293.0&amp;gt;,
  ok: #PID&amp;lt;0.294.0&amp;gt;,
  ok: #PID&amp;lt;0.295.0&amp;gt;,
  ok: #PID&amp;lt;0.296.0&amp;gt;
]
sending message  to 1
sending message  to 2
sending message  to 4
sending message  to 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you pass a list of phone numbers to &lt;code&gt;send_to_all/1&lt;/code&gt; and one of them is 3, the corresponding task will raise an arithmetic error, but other tasks will continue to run. From the results, we can see that we are notified of an arithmetic error in one of the started processes (&lt;code&gt;#PID&amp;lt;0.294.0&amp;gt;&lt;/code&gt;). We also receive printed messages indicating that the messages were sent successfully to numbers 1, 2, 4, and 5. That means that the task started for number 3 encountered an error, but didn&amp;#39;t prevent other processes from performing their tasks.&lt;/p&gt;
&lt;p&gt;This approach enhances concurrency by allowing tasks to run concurrently, while also ensuring that they are isolated processes. This helps to create a more robust system.&lt;/p&gt;
&lt;h2&gt;A Problem: Working with a Series of Tasks&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve seen how we have been able to send messages to the given phone numbers concurrently using &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/Task.html#async/1&quot;&gt;&lt;code&gt;Task.async/1&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/Task.html#start/1&quot;&gt;&lt;code&gt;Task.start/1&lt;/code&gt;&lt;/a&gt;. In the examples provided, &lt;code&gt;send_to_all/1&lt;/code&gt; spawned a process for each task when sending a message. Even though our aim is to leverage concurrency and build a fault-tolerant and robust application, we should also take into consideration that processes don&amp;#39;t share memory.&lt;/p&gt;
&lt;p&gt;The more we increase phone numbers, the more we start a high number of concurrent tasks, each one occupying their own memory. Therefore, increasing the number of concurrent tasks can lead to an application consuming a significant amount of memory. That, in turn, can cause slow application performance and a spike in system usage, degrading system performance and maybe even making other services unresponsive.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s make &lt;code&gt;send_to_all/1&lt;/code&gt; send messages to 1 million phone numbers. But first, we&amp;#39;ll modify it by renaming &lt;code&gt;send_to_all/1&lt;/code&gt; to differentiate the &lt;code&gt;send_to_all/1&lt;/code&gt; using &lt;code&gt;Task.async/1&lt;/code&gt; from the one using &lt;code&gt;Task.start/1&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Sender do
  def send_message(phone_number) do
    # Simulate some processing time
    Process.sleep(3000)
    IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;}
  end

  # Asynchronous version using Task.start/1
  def send_to_all_start(phone_numbers) do
    Enum.each(phone_numbers, fn phone_number -&amp;gt;
      Task.start(fn -&amp;gt; send_message(phone_number) end)
    end)
  end

  # Asynchronous version using Task.async/1
  def send_to_all_async(phone_numbers) do
    phone_numbers
    |&amp;gt; Enum.map(fn phone_number -&amp;gt;
      Task.async(fn -&amp;gt; send_message(phone_number) end)
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this modification, &lt;code&gt;send_to_all_async/1&lt;/code&gt; and &lt;code&gt;send_to_all_start/1&lt;/code&gt; functions have been defined to differentiate the behavior of &lt;code&gt;Task.async/1&lt;/code&gt; and &lt;code&gt;Task.start/1&lt;/code&gt; when attempting to run a million processes.&lt;/p&gt;
&lt;p&gt;Now, open IEx (or recompile it using the &lt;code&gt;recompile()&lt;/code&gt; command if it was already running) and call &lt;code&gt;send_to_all_start/1&lt;/code&gt; with a million phone numbers. We&amp;#39;re not using a real phone number, therefore we simply pass a &lt;code&gt;1..1_000_000&lt;/code&gt; range of numbers.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Sender.send_to_all_start(1..1_000_000)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;06:12:14.067 [error] Too many processes
** (SystemLimitError) a system limit has been reached
    :erlang.spawn(Task.Supervised, :noreply, [{:nonode@nohost, #PID&amp;lt;0.150.0&amp;gt;, #PID&amp;lt;0.150.0&amp;gt;}, [#PID&amp;lt;0.150.0&amp;gt;, #PID&amp;lt;0.142.0&amp;gt;], [#PID&amp;lt;0.150.0&amp;gt;], {:erlang, :apply, [#Function&amp;lt;7.61290973/0 in Sender.send_to_all_start/1&amp;gt;, []]}])
    (elixir 1.15.5) lib/task/supervised.ex:6: Task.Supervised.start/3
    (elixir 1.15.5) lib/enum.ex:4356: Enum.map_range/4
    (elixir 1.15.5) lib/enum.ex:4356: Enum.map_range/4
    (elixir 1.15.5) lib/enum.ex:4356: Enum.map/2
    iex:2: (file)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing we can see is an error message notifying us that too many processes have been started, exceeding the system limit. This is happening as soon as &lt;code&gt;Task.start/1&lt;/code&gt; is invoked for each phone number in the range from 1 to 1,000,000. Success messages have been printed, but they are not showing for all of the phone numbers. The highest number of messages that I can see in the output is &lt;code&gt;262073&lt;/code&gt;. Since the numbers are not sorted, it is easy to miss the highest number. However, the total number of messages sent is around &lt;code&gt;262000&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;What&amp;#39;s Going On Here and How Do We Fix It?&lt;/h3&gt;
&lt;p&gt;We are having issues with starting a million processes because the number of tasks spawned by &lt;code&gt;Task.start/1&lt;/code&gt; exceeds the default limit of processes (262144, for performance and memory-saving reasons) that can be started in BEAM. However, we can override this limit using &lt;code&gt;+P NUM&lt;/code&gt;. This means we can increase the limit by running the command &lt;code&gt;iex --erl &amp;#39;+P 1000000&amp;#39;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To apply this change, close IEx and restart it by running the command &lt;code&gt;iex --erl &amp;#39;+P 1000000&amp;#39; -S mix&lt;/code&gt;. Then, you can call &lt;code&gt;send_to_all_start/1&lt;/code&gt; again, with a range of phone numbers from 1 to &lt;code&gt;1000000&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;sender tracey$ iex --erl &amp;#39;+P 1000000&amp;#39; -S mix
iex &amp;gt; Sender.send_to_all_start(1..1_000_000)
 :ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, the function &lt;code&gt;Enum.each/2&lt;/code&gt; has returned the final output &lt;code&gt;:ok&lt;/code&gt;. Additionally, success messages have been printed for all of the one million phone numbers. It is good that we can override the default system limit, but we must be cautious when increasing the limit, as it can cause the VM to use more memory, potentially leading to performance issues.&lt;/p&gt;
&lt;p&gt;To monitor memory usage before and after a system limit increase, use the &lt;code&gt;:observer.start&lt;/code&gt; command in IEx to open the Observer tool. The Observer shows a spike in memory usage when the system limit is increased.&lt;/p&gt;
&lt;p&gt;Before the system limit increase:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-06/before-limit-inc.png&quot; alt=&quot;before limit increase&quot;/&gt;&lt;/p&gt;
&lt;p&gt;After the system limit increase:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-06/after-limit-inc.png&quot; alt=&quot;after limit increase&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Sending Messages To the Phone Numbers with &lt;code&gt;Task.async/1&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Next, we will use the &lt;code&gt;send_to_all_async/1&lt;/code&gt; function to send messages to a million phone numbers. This function uses &lt;code&gt;Task.async/1&lt;/code&gt; to start a process for each task.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Sender.send_to_all_async(1..1_000_000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;Task.async/1&lt;/code&gt;, you can send a message to all the phone numbers. However, this capability may not be available on all machines, so keep that in mind.&lt;/p&gt;
&lt;p&gt;The Observer shows a spike in memory usage when using &lt;code&gt;Task.async/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-06/with-task-async.png&quot; alt=&quot;with task async&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Running these tasks synchronously works out better in terms of memory usage compared to running them asynchronously when using a combination of &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html&quot;&gt;&lt;code&gt;Enum&lt;/code&gt;&lt;/a&gt; with either &lt;code&gt;Task.async/1&lt;/code&gt; or &lt;code&gt;Task.start/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-06/running-synchronously.png&quot; alt=&quot;running synchronously&quot;/&gt;&lt;/p&gt;
&lt;p&gt;When using &lt;code&gt;Task.start/&lt;/code&gt; or &lt;code&gt;Task.async/1&lt;/code&gt; to start a process for each task, you&amp;#39;re essentially creating a separate process for each message you want to send. While this can be an efficient way to handle concurrency, it can also lead to increased memory usage, especially when dealing with a large number of tasks simultaneously.&lt;/p&gt;
&lt;p&gt;The spike in memory usage we&amp;#39;re seeing in the Observer is likely due to the fact that each process created by &lt;code&gt;Task.async/1&lt;/code&gt; and &lt;code&gt;Task.start/1&lt;/code&gt; consumes memory. With a million phone numbers, you&amp;#39;re creating a million processes, which can quickly exhaust available memory, especially if each process is doing significant work or holding onto a large amount of data.&lt;/p&gt;
&lt;h2&gt;The Solution: Use &lt;code&gt;Task.async_stream/3&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;When utilizing Task processes, the goal is to achieve concurrency to efficiently send messages to designated phone numbers. However, it is important to be mindful of system resources and avoid sudden increases in pressure.&lt;/p&gt;
&lt;p&gt;Fortunately, the Task module provides a useful feature known as &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/Task.html#async_stream/3&quot;&gt;&lt;code&gt;Task.async_stream/3&lt;/code&gt;&lt;/a&gt;. It works similarly to &lt;code&gt;Enum.map/2&lt;/code&gt; and &lt;code&gt;Task.async/2&lt;/code&gt; combined, as it creates task processes from a given list of items.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;Task.async_stream/3&lt;/code&gt;, you can perform the task for each item in the list concurrently, by starting a process. The only difference is that you can set a limit on the number of processes running at the same time with this function.&lt;/p&gt;
&lt;p&gt;For instance, suppose the message application needs to send messages to 100 phone numbers using &lt;code&gt;Task.async_stream/3&lt;/code&gt;. In this case, we can set the concurrency limit to 5, which means that, at most, only 5 processes will start to send messages to the given phone numbers at the same time.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Task.async_stream/3&lt;/code&gt; takes in three arguments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enumerable: This argument represents the collection of items that you want to process concurrently. It can be an &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html&quot;&gt;Enum&lt;/a&gt; or a &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Stream.html&quot;&gt;Stream&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Anonymous function: This must take a single argument that represents an element of the enumerable. The function is applied to each enumerable element. It defines the task to be executed concurrently for each item.&lt;/li&gt;
&lt;li&gt;Options, used to control the level of concurrency, the time tasks are allowed to run, ordering of the results and the action to take when a task times out.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;Task.async_stream/3&lt;/code&gt; returns a stream, which is a lazy enumerable. Therefore, transformations or computations on the stream are not performed as soon as the stream is created. Instead, they are performed until the stream is explicitly consumed or operated upon.&lt;/p&gt;
&lt;h3&gt;An Example Using &lt;code&gt;Task.async_stream/3&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Here&amp;#39;s an example of using &lt;code&gt;Task.async_stream/3&lt;/code&gt; in IEx:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Task.async_stream(1..5, fn phone_number -&amp;gt; send_message(phone_number) end)
#Function&amp;lt;3.112246596/2 in Task.build_stream/3&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result that&amp;#39;s returned is a &lt;code&gt;stream&lt;/code&gt;. To run this stream, we can use &lt;a href=&quot;https://hexdocs.pm/elixir/Stream.html#run/1&quot;&gt;&lt;code&gt;Stream.run/1&lt;/code&gt;&lt;/a&gt;, which returns &lt;code&gt;:ok&lt;/code&gt; and isn&amp;#39;t useful when we&amp;#39;re not interested in the final result. Another alternative is to use the Enum functions. This is useful when you intend to perform other tasks with the expected result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; 1..5 |&amp;gt; Task.async_stream(fn phone_number -&amp;gt; send_message(phone_number) end) |&amp;gt; Stream.run()
sending message  to 1
sending message  to 2
sending message  to 3
sending message  to 4
sending message  to 5
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Stream.run/1&lt;/code&gt; is used to run the stream without collecting the result. The messages are sent to the given phone numbers and once all tasks are completed, &lt;code&gt;:ok&lt;/code&gt; is returned.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; 1..5 |&amp;gt; Task.async_stream(fn phone_number -&amp;gt; send_message(phone_number) end) |&amp;gt; Enum.to_list
sending message  to 1
sending message  to 2
sending message  to 3
sending message  to 4
sending message  to 5

[
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/Enum.html#to_list/1&quot;&gt;&lt;code&gt;Enum.to_list/1&lt;/code&gt;&lt;/a&gt; runs the stream and collects the results into a list.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Task.async_stream/3&lt;/code&gt; accepts a list of options. When not explicitly passed, the options default to their default values.
Let&amp;#39;s dive further into the options passed to &lt;code&gt;Task.async_stream/3&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;:max_concurrency&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;:max_concurrency&lt;/code&gt; is responsible for setting a limit on the number of processes running at the same time. Its value defaults to the number of logical cores available in a system.&lt;/p&gt;
&lt;p&gt;When running &lt;code&gt;Task.async_stream/3&lt;/code&gt; in IEx with a &lt;code&gt;1..20&lt;/code&gt; range of phone numbers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt;  Task.async_stream(1..20, fn phone_number -&amp;gt; send_message(phone_number) end) |&amp;gt; Stream.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I noticed that the number of items processed at the same time was in a batch of 10 until completion. This number can differ depending on the machine used, so don&amp;#39;t be surprised if you&amp;#39;re seeing a batch of 20 or even 5 items processed simultaneously in your machine. This is because of the logical cores available in different machines. To confirm the number of logical cores available, use &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/System.html#schedulers_online/0&quot;&gt;&lt;code&gt;System.schedulers_online/0&lt;/code&gt;&lt;/a&gt;. For machines whose CPU has less than 4 logical cores, &lt;code&gt;Task.async_stream/3&lt;/code&gt; will appear to be slower.&lt;/p&gt;
&lt;p&gt;We can emulate the slow performance by setting &lt;code&gt;:max_concurrency&lt;/code&gt; to a value less than 4.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt;  Task.async_stream(1..20, fn phone_number -&amp;gt; send_message(phone_number) end, max_concurrency: 2) |&amp;gt; Stream.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the concurrency limit is set to 2, it takes more time to complete compared to using the default value set, 10. This is due to the fact that with a lower concurrency limit, fewer tasks are processed concurrently.&lt;/p&gt;
&lt;p&gt;When setting &lt;code&gt;max_concurrency&lt;/code&gt;, consider your system resources. Verify that the system has enough resources to handle the specified concurrency limit effectively and also bear in mind the need for performance. Depending on what works for your use case, you can decrease or increase the concurrency limit.&lt;/p&gt;
&lt;p&gt;Our application aims to send messages to a million phone numbers. At present, the &lt;code&gt;max_concurrency&lt;/code&gt; setting on my machine is set to 10 and is working satisfactorily. However, it is taking a long time to process all the messages. After 17 minutes, only about 3,000 messages have been sent. To improve the processing speed, we need to increase the concurrency limit. I shall set it to 100, allowing more items to be processed concurrently, while also ensuring we do not overload the system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; 1..20
    &amp;gt; |&amp;gt; Task.async_stream( fn phone_number -&amp;gt; send_message(phone_number) end, max_concurrency: 100)
    &amp;gt; |&amp;gt; Stream.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After increasing the &lt;code&gt;max_concurrency&lt;/code&gt; to 100:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In 4 minutes, about 6,000 messages were sent.&lt;/li&gt;
&lt;li&gt;There is no spike in memory allocation when we open the &lt;code&gt;observer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s the observer memory allocation when &lt;code&gt;max_concurrency&lt;/code&gt; is set to 10:
&lt;img src=&quot;/images/blog/2024-06/concurrency-limit-10.png&quot; alt=&quot;Concurrency limit of 10&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And here it is when &lt;code&gt;max_concurrency&lt;/code&gt; is set to 100:
&lt;img src=&quot;/images/blog/2024-06/concurrency-limit-100.png&quot; alt=&quot;concurrency limit of 100&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;:ordered&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;When we execute this code in &lt;code&gt;IEx&lt;/code&gt;, you will notice that the results are returned in the same order as the input data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; 1..5
    &amp;gt; |&amp;gt; Task.async_stream( fn phone_number -&amp;gt; send_message(phone_number) end, max_concurrency: 100)
    &amp;gt; |&amp;gt; Enum.to_list

sending message  to 1
sending message  to 2
sending message  to 3
sending message  to 4
sending message  to 5

[
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;},
:ok, {:ok, &amp;quot;sent&amp;quot;}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because we have the &lt;code&gt;:ordered&lt;/code&gt; option set to &lt;code&gt;true&lt;/code&gt; by default in the &lt;code&gt;Task.async_stream/3&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;However, setting &lt;code&gt;:ordered&lt;/code&gt; to true can result in slower processing if a task takes longer to complete. This is because &lt;code&gt;Task.async_stream/3&lt;/code&gt; will wait for a slow task to finish before moving on to the next one. Therefore, it is important to consider the trade-off between ordered results and processing speed when using this function.&lt;/p&gt;
&lt;p&gt;To improve processing speed, you can disable ordering by setting the &lt;code&gt;:ordered&lt;/code&gt; option to &lt;code&gt;false&lt;/code&gt;. This way, &lt;code&gt;Task.async_stream/3&lt;/code&gt; won&amp;#39;t wait for a slow task to complete processing before moving on to the next task.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s introduce a slow process in our &lt;code&gt;Sender&lt;/code&gt; application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Sender do
  def send_message(3) do
    # Simulate slow processing time
    Process.sleep(4000)
    IO.puts(&amp;quot;Sending message to 3&amp;quot;)

    {:ok, &amp;quot;sent&amp;quot;, 3}
  end

  def send_message(phone_number) do
    # Simulate some processing time
    Process.sleep(3000)
    IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, phone_number}
  end

  # Asynchronous version using Task.async_stream/3
  def send_to_all(phone_numbers) do
    phone_numbers
    |&amp;gt; Task.async_stream(fn phone_number -&amp;gt; send_message(phone_number) end)
    |&amp;gt; Enum.to_list()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;send_message/1&lt;/code&gt; function accepts one argument, a phone number. If the phone number is 3, the function simulates a slow process by sleeping for 4 seconds. Otherwise, it simulates a regular process by sleeping for 3 seconds. The output result includes the phone number that&amp;#39;s being processed, which allows us to check the order of the returned result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Sender.send_to_all(1..5)

sending message  to 1
sending message  to 2
sending message  to 4
sending message  to 5
sending message  to 3

[
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 1},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 2},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 3},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 4},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 5}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The print message of number 3 is displayed last, indicating that it took longer to process before sending. However, the collected list is returned in the same order as the given input. This means that, while number 3 took longer to complete, numbers 4 and 5 had to wait before being operated on.&lt;/p&gt;
&lt;p&gt;In our case, we want to check whether the status of the messages sent to the given phone numbers was successful or not. To speed up things, let&amp;#39;s disable the &lt;code&gt;:ordered&lt;/code&gt; option by setting it to &lt;code&gt;false&lt;/code&gt;, since we don&amp;#39;t care about the order.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Sender do
  def send_message(3) do
    # Simulate slow processing time
    Process.sleep(4000)
    IO.puts(&amp;quot;Sending message to 3&amp;quot;)

    {:ok, &amp;quot;sent&amp;quot;, 3}
  end

  def send_message(phone_number) do
    # Simulate some processing time
    Process.sleep(3000)
    IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, phone_number}
  end

  # Asynchronous version using Task.async_stream/3
  def send_to_all(phone_numbers) do
    phone_numbers
    |&amp;gt; Task.async_stream(fn phone_number -&amp;gt; send_message(phone_number) end, ordered: false)
    |&amp;gt; Enum.to_list()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Sender.send_to_all(1..5)

sending message  to 1
sending message  to 2
sending message  to 4
sending message  to 5
sending message  to 3

[
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 1},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 2},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 4},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 5},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 3},
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The number 3 is collected last in the returned result. This way, we can be sure that &lt;code&gt;Task.async_stream/3&lt;/code&gt; won&amp;#39;t be idle waiting for the processing of number 3 to complete, before moving to the next.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;:timeout&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Task.async_stream/3&lt;/code&gt; function has a &lt;code&gt;:timeout&lt;/code&gt; option which sets a limit on how long each task can run. By default, the timeout is set to 5000 milliseconds or 5 seconds. You can specify the time limit in milliseconds or set it to &lt;code&gt;:infinity&lt;/code&gt; if you want to allow the task to run indefinitely. If a task takes longer than the specified timeout, it will raise an exception and terminate the current process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Sender do
  def send_message(3) do
    # Simulate slow processing time
    Process.sleep(7000)
    IO.puts(&amp;quot;Sending message to 3&amp;quot;)

    {:ok, &amp;quot;sent&amp;quot;, 3}
  end

  def send_message(phone_number) do
    # Simulate some processing time
    Process.sleep(3000)
    IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, phone_number}
  end

  # Asynchronous version using Task.async_stream/3
  def send_to_all(phone_numbers) do
    phone_numbers
    |&amp;gt; Task.async_stream(fn phone_number -&amp;gt; send_message(phone_number) end, ordered: false)
    |&amp;gt; Enum.to_list()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the processing time of the slow process/task is increased to 7000ms, which exceeds the default timeout in &lt;code&gt;Task.async_stream/3&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Sender.send_to_all(1..5)

sending message  to 1
sending message  to 2
sending message  to 4
sending message  to 5

** (exit) exited in: Task.Supervised.stream(5000)
    ** (EXIT) time out
    (elixir 1.15.5) lib/task/supervised.ex:314: Task.Supervised.stream_reduce/7
    (elixir 1.15.5) lib/enum.ex:4387: Enum.reverse/1
    (elixir 1.15.5) lib/enum.ex:3704: Enum.to_list/1
    iex:3: (file)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we execute the &lt;code&gt;Sender.send_to_all(1..5)&lt;/code&gt; function in IEx, an exception is raised, which stops the stream and crashes the current process. This is because the slow task takes more than 5000ms to complete, while &lt;code&gt;Task.async_stream/3&lt;/code&gt; has a timeout limit of 5000ms.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;:on_timeout&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s difficult to predict the duration of a task, as several factors can contribute to its slow processing. For instance, processing a large amount of data can be time-consuming, as can waiting for a slow third-party API to respond.&lt;/p&gt;
&lt;p&gt;Instead of allowing &lt;code&gt;Task.async_stream/3&lt;/code&gt; to raise an exception that stops the stream, we can use the &lt;code&gt;:on_timeout&lt;/code&gt; option by setting it to &lt;code&gt;:kill_task&lt;/code&gt;. This option determines the action to take when the task times out. Setting it to &lt;code&gt;:kill_task&lt;/code&gt; will cause &lt;code&gt;Task.async_stream/3&lt;/code&gt; to ignore the process that exits with a timeout and continue with other tasks.&lt;/p&gt;
&lt;p&gt;By default, it&amp;#39;s set to &lt;code&gt;:exit&lt;/code&gt;. This results in the task exceeding the timeout to stop the stream and crash the current process, as seen with the &lt;code&gt;:timeout&lt;/code&gt; option.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Sender do
  def send_message(3) do
    # Simulate slow processing time
    Process.sleep(7000)
    IO.puts(&amp;quot;Sending message to #{3}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, 3}
  end

  def send_message(phone_number) do
    # Simulate some processing time
    Process.sleep(3000)
    IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, phone_number}
  end

  # Asynchronous version using Task.async_stream/3
  def send_to_all(phone_numbers) do
    phone_numbers
    |&amp;gt; Task.async_stream(fn phone_number -&amp;gt; send_message(phone_number) end,
      ordered: false,
      on_timeout: :kill_task
    )
    |&amp;gt; Enum.to_list()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the &lt;code&gt;:on_timeout&lt;/code&gt; option and set it to &lt;code&gt;:kill_task&lt;/code&gt; in &lt;code&gt;Task.async_stream/3&lt;/code&gt;. Then, execute &lt;code&gt;Sender.send_to_all(1..5)&lt;/code&gt; in IEx. We can observe that the other tasks are processed completely, while the slow process is ignored, and returns &lt;code&gt;{:exit, :timeout}&lt;/code&gt; instead of crashing.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; Sender.send_to_all(1..5)

sending message  to 1
sending message  to 2
sending message  to 4
sending message  to 5

[
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 1},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 2},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 4},
{:ok, {:ok, &amp;quot;sent&amp;quot;}, 5},
exit: :timeout
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we wrap up, let&amp;#39;s take a very quick look at monitoring memory using Observer.&lt;/p&gt;
&lt;h2&gt;Monitor Memory with Erlang Observer&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s use Erlang Observer to monitor memory allocation. We can compare memory usage when defining the &lt;code&gt;send_to_all/1&lt;/code&gt; function using &lt;code&gt;Task.async_stream/3&lt;/code&gt; and using a combination of &lt;code&gt;Enum.map/2&lt;/code&gt; and &lt;code&gt;Task.async/1&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Sender do
  def send_message(3) do
    # Simulate slow processing time
    Process.sleep(7000)
    IO.puts(&amp;quot;Sending message to #{3}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, 3}
  end

  def send_message(phone_number) do
    # Simulate some processing time
    Process.sleep(3000)
    IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, phone_number}
  end

  # Asynchronous version using Task.async_stream/3
  def send_to_all(phone_numbers) do
    phone_numbers
    |&amp;gt; Task.async_stream(fn phone_number -&amp;gt; send_message(phone_number) end,
      max_concurrency: 100,
      ordered: false,
      on_timeout: :kill_task
    )
    |&amp;gt; Stream.run()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Sender do
  def send_message(3) do
    # Simulate slow processing time
    Process.sleep(7000)
    IO.puts(&amp;quot;Sending message to #{3}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;, 3}
  end

  def send_message(phone_number) do
    # Simulate some processing time
    Process.sleep(3000)
    IO.puts(&amp;quot;Sending message to #{phone_number}&amp;quot;)
    {:ok, &amp;quot;sent&amp;quot;}
  end

  # Asynchronous version using Task.async/1
  def send_to_all(phone_numbers) do
    phone_numbers
    |&amp;gt; Enum.map(fn phone_number -&amp;gt;
      Task.async(fn -&amp;gt; send_message(phone_number) end)
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-06/efficient.png&quot; alt=&quot;efficient&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-06/inefficient.png&quot; alt=&quot;inefficient&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The combination of &lt;code&gt;Task.async/1&lt;/code&gt; and &lt;code&gt;Enum.map/2&lt;/code&gt; can significantly impact memory consumption compared to using &lt;code&gt;Task.async_stream/3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Task.async_stream/3&lt;/code&gt; is a powerful tool for effectively utilizing concurrency without overloading system resources when working with a series of tasks.&lt;/p&gt;
&lt;p&gt;Here are a couple of benefits of using &lt;code&gt;Task.async_stream/3&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It prevents sudden spikes in system usage: By setting the concurrency limit option, you can control the number of concurrent tasks being executed at any given time. This helps prevent the system from becoming overwhelmed with too many tasks running simultaneously, which could lead to spikes in resource usage, such as memory or CPU.&lt;/li&gt;
&lt;li&gt;It handles back pressure: Back pressure occurs when there&amp;#39;s resistance to the progress of turning input to output. By setting the concurrency limit, &lt;code&gt;Task.async_stream/3&lt;/code&gt; ensures that tasks are processed at a manageable rate, preventing resource exhaustion.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Elixir has several tools that are useful when it comes to leveraging concurrency, and Task processes is one of them.&lt;/p&gt;
&lt;p&gt;In this post, we explored the concept of concurrency and some of the issues we might face when dealing with a series of tasks while using concurrency.&lt;/p&gt;
&lt;p&gt;We then explored the use of &lt;code&gt;Task.async_stream/3&lt;/code&gt;, a Task module function that is effective in handling a large number of tasks, as it provides both concurrency and performance.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Advanced Dependency Injection in Elixir with Rewire</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/06/11/advanced-dependency-injection-in-elixir-with-rewire.html"/>
    <id>https://blog.appsignal.com/2024/06/11/advanced-dependency-injection-in-elixir-with-rewire.html</id>
    <published>2024-06-11T00:00:00+00:00</published>
    <updated>2024-06-11T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Dependency injection can prove useful in Elixir. In this second part of a two-part series, we&#039;ll look at some basic concepts, core principles, and types of dependency injection.</summary>
    <content type="html">&lt;p&gt;In our last post, we explored how Dependency Injection (DI) is a powerful design pattern that can improve our ExUnit tests.&lt;/p&gt;
&lt;p&gt;In this article, we will dive deeper into the topic of DI in Elixir, focusing on the Rewire library for Elixir projects.&lt;/p&gt;
&lt;p&gt;We will cover Rewire&amp;#39;s core concepts, how to get started with it, and practical examples. We will also see how to use Rewire alongside Mox.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Introduction to Rewire&lt;/h2&gt;
&lt;p&gt;One of the challenges we faced in our previous article was the lack of a structured way to define and inject dependencies into our modules. We had to manually define our mocks for testing.&lt;/p&gt;
&lt;p&gt;This is where Rewire and Mox come into play:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rewire&lt;/strong&gt; provides a more structured and flexible way to implement DI in Elixir projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mox&lt;/strong&gt; is a library that allows us to define mocks for our tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combining these two tools can significantly improve the testability and modularity of our Elixir applications.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started by setting up a sample project that leverages both libraries.&lt;/p&gt;
&lt;h2&gt;Why Use Rewire and Mox for Elixir?&lt;/h2&gt;
&lt;p&gt;To recap part one of the series, we discussed the benefits of DI for testability and modularity. We saw how we can use pass-in dependencies via function parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have the &lt;code&gt;EmailScanner&lt;/code&gt; module that relies on a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if an email is spam or not:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScanner do
  def scan_email(spam_filter_service, email) do
    spam_filter_service.check_spam(email)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;We have the &lt;code&gt;SpamFilterService&lt;/code&gt; module that implements the spam checking logic:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SpamFilterService do
  def check_spam(email_content) do
    String.contains?(email_content, &amp;quot;spam&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;We also have a &lt;code&gt;MockSpamFilterService&lt;/code&gt; module that implements the &lt;code&gt;SpamFilterService&lt;/code&gt; behaviour for testing purposes:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MockSpamFilterService do
  def check_spam(_email), do: false
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Finally, we have a test that uses the &lt;code&gt;MockSpamFilterService&lt;/code&gt; to test the &lt;code&gt;EmailScanner&lt;/code&gt; module:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScannerTest do
  use ExUnit.Case

  test &amp;quot;scan_email with non-spam email returns false&amp;quot; do
    non_spam_email = %Email{content: &amp;quot;Hello, world!&amp;quot;}
    assert false == EmailScanner.scan_email(MockSpamFilterService, non_spam_email)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Elixir, modules are stateless, so the primary way to pass dependencies to a module is via function parameters. While Elixir modules can have attributes, these are used for compile-time information and metadata, not for holding runtime state.&lt;/p&gt;
&lt;p&gt;Take the &lt;code&gt;EmailScanner&lt;/code&gt; module, for example. We have to pass the &lt;code&gt;SpamFilterService&lt;/code&gt; as a parameter to the &lt;code&gt;scan_email&lt;/code&gt; function. This is unnecessary, as the only reason to have this function parameter is to make the module testable.&lt;/p&gt;
&lt;p&gt;Additionally, it creates a few problems with code readability and navigation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Because the module is expecting &lt;code&gt;SpamFilterService&lt;/code&gt; as a parameter, we can&amp;#39;t easily see what the module depends on.&lt;/li&gt;
&lt;li&gt;The compiler can&amp;#39;t catch issues with the module implementation, because we can pass any module that implements the &lt;code&gt;SpamFilterService&lt;/code&gt; behaviour.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This approach might work well for small projects, but as our project grows, we might find ourselves repeating the same pattern over and over again. With &lt;a href=&quot;https://github.com/stephanos/rewire&quot;&gt;Rewire&lt;/a&gt;, we don&amp;#39;t have to worry about these issues. We can just focus on writing clean and maintainable code while keeping any testing concerns, mocks, and stubs in our test files.&lt;/p&gt;
&lt;h2&gt;Getting Started with Rewire and Mox in Your Elixir Project&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s now dive into using Rewire and Mox in practice.&lt;/p&gt;
&lt;h3&gt;Step 1: Create a New Elixir Project&lt;/h3&gt;
&lt;p&gt;Before incorporating Rewire and Mox, create a new Elixir project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix new email_scanner
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command generates a new Elixir project named &lt;code&gt;email_scanner&lt;/code&gt;, including a supervision tree structure.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Step 2: Add Dependencies&lt;/h3&gt;
&lt;p&gt;To use Rewire and Mox, you need to add them to your project&amp;#39;s dependencies. Update your &lt;code&gt;mix.exs&lt;/code&gt; file as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:rewire, &amp;quot;~&amp;gt; 1.0&amp;quot;, only: :test},
    {:mox, &amp;quot;~&amp;gt; 1.0&amp;quot;, only: :test}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After updating the dependencies, run &lt;code&gt;mix deps.get&lt;/code&gt; in your terminal to fetch and install them.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s define our two primary modules:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScanner do
  def filter_email(email) do
    email
    |&amp;gt; mark_as_important()
    |&amp;gt; SpamFilterService.check_spam()
  end

  defp mark_as_important(email) do
    important_senders = [&amp;quot;boss@example.com&amp;quot;, &amp;quot;hr@example.com&amp;quot;]

    updated_email =
      if Enum.any?(important_senders, fn sender -&amp;gt; sender == email.sender end) do
        %{email | important: true}
      else
        email
      end

    updated_email
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are making our code example a bit more realistic. The &lt;code&gt;filter_email&lt;/code&gt; function marks emails from important senders as important and checks if the email is spam using the &lt;code&gt;SpamFilterService&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;Next, we&amp;#39;ll define the &lt;code&gt;SpamFilterService&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SpamFilterService do
  def check_spam(email_content) do
    String.contains?(email_content, &amp;quot;spam&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s create a basic test for the &lt;code&gt;EmailScanner&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScannerTest do
  use ExUnit.Case

  describe &amp;quot;filter_email/2&amp;quot; do
    test &amp;quot;marks email as important from specific sender and checks for spam&amp;quot; do
      important_sender_email = %{sender: &amp;quot;boss@example.com&amp;quot;, content: &amp;quot;Please review the attached report.&amp;quot;, important: false}
      non_important_sender_email = %{sender: &amp;quot;random@example.com&amp;quot;, content: &amp;quot;Check out these deals!&amp;quot;, important: false}

      # Filtering emails sent from the important sender
      assert %{important: true, is_spam: false} = EmailScanner.filter_email(important_sender_email)

      # Filtering emails sent from a non-important sender
      assert %{important: false, is_spam: false} = EmailScanner.filter_email(non_important_sender_email)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, the &lt;code&gt;EmailScanner&lt;/code&gt; module relies on the &lt;code&gt;SpamFilterService&lt;/code&gt; module to check if an email is spam or not. However, we can&amp;#39;t test the &lt;code&gt;EmailScanner&lt;/code&gt; module without also testing the &lt;code&gt;SpamFilterService&lt;/code&gt; module, which is not ideal.&lt;/p&gt;
&lt;p&gt;We need to mock the &lt;code&gt;SpamFilterService&lt;/code&gt; module so that we can test the &lt;code&gt;EmailScanner&lt;/code&gt; module in isolation.&lt;/p&gt;
&lt;h3&gt;Step 3: Configuring Mox&lt;/h3&gt;
&lt;p&gt;Mox requires a bit of setup in your test configuration. Open or create a &lt;code&gt;test/test_helper.exs&lt;/code&gt; file and add the following line to define a mock based on a protocol or behaviour your project uses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;ExUnit.start()
Mox.defmock(EmailScanner.SpamFilterServiceMock, for: EmailScanner.SpamFilterService)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mox makes it easy for us to generate mocks based on behaviours or protocols, which is essential for testing modules that rely on these abstractions.&lt;/p&gt;
&lt;p&gt;Once our mock is defined, we can use it in our tests instead of the real implementation. With Rewire, we can inject these mocks into our modules without relying on function parameters.&lt;/p&gt;
&lt;h2&gt;Core Concepts of Rewire&lt;/h2&gt;
&lt;p&gt;Rewire simplifies the DI process in Elixir by providing a macro-based approach to define and inject dependencies. It fits seamlessly within Elixir’s ecosystem, promoting clean and maintainable code.&lt;/p&gt;
&lt;h3&gt;Dependency Injection with Rewire in the &lt;code&gt;EmailScanner&lt;/code&gt; Module&lt;/h3&gt;
&lt;p&gt;Let’s implement the &lt;code&gt;EmailScanner&lt;/code&gt; module, which relies on a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if an email is spam or not. Using Rewire, we can easily inject this dependency. Take a look at the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScanner do
  def filter_email(email) do
    email
    |&amp;gt; mark_as_important()
    |&amp;gt; SpamFilterService.check_spam()
  end

  defp mark_as_important(email) do
    important_senders = [&amp;quot;boss@example.com&amp;quot;, &amp;quot;hr@example.com&amp;quot;]

    updated_email =
      if Enum.any?(important_senders, fn sender -&amp;gt; sender == email.sender end) do
        %{email | important: true}
      else
        email
      end

    updated_email
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Mocking with Mox for Testing&lt;/h3&gt;
&lt;p&gt;To test the &lt;code&gt;EmailScanner&lt;/code&gt; filter function, we can use Mox to mock the &lt;code&gt;SpamFilterService&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScannerTest do
  use ExUnit.Case

  import Rewire
  import Mox

  rewire EmailScanner, SpamFilterService: SpamFilterServiceMock

  # Ensure mocks are verified after each test
  setup :verify_on_exit!

  describe &amp;quot;filter_email/2&amp;quot; do
    test &amp;quot;marks email as important from specific sender and checks for spam&amp;quot; do
      important_sender_email = %{sender: &amp;quot;boss@example.com&amp;quot;, content: &amp;quot;Please review the attached report.&amp;quot;, important: false}
      non_important_sender_email = %{sender: &amp;quot;random@example.com&amp;quot;, content: &amp;quot;Check out these deals!&amp;quot;, important: false}

      # Stub the SpamFilter service to return false for all emails
      stub(SpamFilterServiceMock, :check_spam, fn _email -&amp;gt; :false end)

      # Filtering emails sent from the important sender
      assert %{important: true, is_spam: false} = EmailScanner.filter_email(important_sender_email)

      # Filtering emails sent from a non-important sender
      assert %{important: false, is_spam: false} = EmailScanner.filter_email(non_important_sender_email)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s break down what is happening in the above test:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rewire EmailScanner, SpamFilterService: SpamFilterServiceMock&lt;/code&gt;: This line uses Rewire to replace the &lt;code&gt;SpamFilterService&lt;/code&gt; dependency in the &lt;code&gt;EmailScanner&lt;/code&gt; module with &lt;code&gt;SpamFilterServiceMock&lt;/code&gt; for the scope of this test module. It effectively changes the behavior of &lt;code&gt;EmailScanner&lt;/code&gt; to use the mock service instead of its real dependency.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setup :verify_on_exit!&lt;/code&gt;: A setup callback that ensures all expectations on mocks (defined using Mox) are met by the end of each test, or else the test fails. This is crucial for verifying that the mocked functions are called as expected.&lt;/li&gt;
&lt;li&gt;Then, we define a test case that:&lt;ul&gt;
&lt;li&gt;Creates two email maps, one from an &amp;quot;important&amp;quot; sender and one from a &amp;quot;non-important&amp;quot; sender.&lt;/li&gt;
&lt;li&gt;Uses stub to define the behavior of the &lt;code&gt;SpamFilterServiceMock&lt;/code&gt;, so &lt;code&gt;check_spam/1&lt;/code&gt; always returns &lt;code&gt;false&lt;/code&gt;, simulating a scenario where no email is considered spam.&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;filter_email/2&lt;/code&gt; on both emails, expecting the function to correctly identify and mark the important email and to correctly interact with the spam filter (mocked to always return &lt;code&gt;false&lt;/code&gt; for spam checks).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Under the hood, Rewire is doing a couple of interesting things. First, it&amp;#39;s important to understand the philosophy behind Rewire and the approach the author decided to take. &lt;code&gt;rewire&lt;/code&gt; works by using macros to create a copy of the module. So, for every test, Rewire creates a new module with the specified stubs.&lt;/p&gt;
&lt;p&gt;Creating a copy of each module instead of overriding the original module allows us to run tests in parallel without any side effects.&lt;/p&gt;
&lt;h2&gt;Things to Consider When Using Rewire and Mox&lt;/h2&gt;
&lt;p&gt;When using Rewire and Mox in your Elixir projects, consider the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Asynchronous Testing Compatibility:&lt;/strong&gt;
Rewire fully supports asynchronous testing with &lt;code&gt;async: true&lt;/code&gt;. Unlike global overrides used by tools like Meck, Rewire creates a separate module copy for each test. This ensures that tests can run in parallel without interfering with each other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration with Mox:&lt;/strong&gt;
Rewire complements Mox perfectly by focusing on dependency injection without dictating the source of the mock module. This synergy allows for efficient and seamless integration between the two, making them an excellent pair for Elixir testing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Impact on Test Speed:&lt;/strong&gt;
Rewire might slightly slow down your tests, although the effect is typically minimal. Comprehensive performance data from large codebases is still pending.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Coverage Accuracy:&lt;/strong&gt;
Yes, test coverage is accurately reported with Rewire, ensuring that you can trust your test coverage metrics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility with Stateful Processes:&lt;/strong&gt;
Rewire works well with stateful processes, provided that these processes are started after their module has been rewired. For processes started beforehand (like a Phoenix controller), Rewire may not be effective since rewiring can no longer be applied. It&amp;#39;s recommended to use Rewire primarily for unit tests where this limitation doesn&amp;#39;t apply.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Erlang Module Rewiring:&lt;/strong&gt;
Rewire cannot directly rewire Erlang modules. However, it allows for Erlang module references to be replaced within Elixir modules, offering a workaround for this limitation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling Nested Modules:&lt;/strong&gt;
Rewire will only replace dependencies within the specifically rewired module. Surrounding or nested modules will remain unaffected, maintaining references to the original modules. For complete control, you may need to rewire these modules individually.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Formatter Configuration for Rewire:&lt;/strong&gt;
To prevent mix format from adding parentheses around Rewire, update your &lt;code&gt;.formatter.exs&lt;/code&gt; file with &lt;code&gt;import_deps: [:rewire]&lt;/code&gt;. This ensures that Rewire syntax is correctly formatted without unnecessary parentheses.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we&amp;#39;ve explored how Rewire and Mox can help with dependency injection in Elixir.&lt;/p&gt;
&lt;p&gt;Stephan Behnke, the creator of Rewire, was motivated by a desire for a more elegant solution to dependency injection in Elixir, especially for unit testing. I believe he succeeded in providing a great tool for the Elixir community.&lt;/p&gt;
&lt;p&gt;That said, Rewire is not a silver bullet and it might not be the right tool for every project. It is important to evaluate Rewire alongside tools like &lt;a href=&quot;https://github.com/eproxus/meck&quot;&gt;Meck&lt;/a&gt; and make a decision based on your project and team&amp;#39;s needs.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Using Dependency Injection in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/05/21/using-dependency-injection-in-elixir.html"/>
    <id>https://blog.appsignal.com/2024/05/21/using-dependency-injection-in-elixir.html</id>
    <published>2024-05-21T00:00:00+00:00</published>
    <updated>2024-05-21T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Dependency injection can prove useful in Elixir. In this first part of a two-part series, we&#039;ll look at some basic concepts, core principles, and types of dependency injection.</summary>
    <content type="html">&lt;p&gt;While controversial in functional programming, dependency injection can be a useful pattern in Elixir for managing dependencies and improving testability.&lt;/p&gt;
&lt;p&gt;In this, the first part of a two-part series, we will cover the basic concepts, core principles, and types of dependency injection. We&amp;#39;ll explore its benefits in terms of modularity, testability, and maintainability.&lt;/p&gt;
&lt;p&gt;Then, we will look into a specific scenario where dependency injection can be beneficial, in this case, testing.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s first explain what dependency injection is.&lt;/p&gt;
&lt;h2&gt;What Is Dependency Injection?&lt;/h2&gt;
&lt;p&gt;Dependency Injection (DI) is a software design pattern that involves supplying an external dependency to a component rather than allowing the component to create the dependency itself. This pattern is a form of Inversion of Control (IoC), where control over the dependencies is inverted from the component to an external entity.&lt;/p&gt;
&lt;p&gt;The main goal of DI is to reduce coupling between components, making our system more modular, flexible to changes, and easier to test.&lt;/p&gt;
&lt;p&gt;These are the core concepts of dependency injection:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dependency&lt;/strong&gt;: An entity that another entity depends on to function properly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Injector&lt;/strong&gt;: The mechanism that injects dependencies into a component.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client&lt;/strong&gt;: The component that depends on the provided dependencies to operate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service&lt;/strong&gt;: The dependency that the client component uses.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Types of Dependency Injection&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Constructor Injection&lt;/strong&gt;: The dependencies are provided through the component&amp;#39;s constructor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Setter Injection&lt;/strong&gt;: The dependencies are provided through setter methods or properties.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Interface Injection&lt;/strong&gt;: The dependency provides an injector method that will inject the dependency into any client passed to it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Advantages of Dependency Injection&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reduced Coupling&lt;/strong&gt;: By decoupling components from their dependencies, systems become more modular, allowing for easier maintenance and scalability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Increased Flexibility&lt;/strong&gt;: Changing or updating dependencies does not require changes to the dependent components, making the system more adaptable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved Testability&lt;/strong&gt;: Dependencies can be easily mocked or stubbed in tests, allowing for more isolated and reliable testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;How Dependency Injection Works&lt;/h3&gt;
&lt;p&gt;There are four steps you should take to leverage dependency injection in your program or service:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Define the Service Interfaces&lt;/strong&gt;: These interfaces represent the abstract contracts that services must fulfill.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implement the Services&lt;/strong&gt;: Concrete implementations of the service interfaces are developed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configure the Injector&lt;/strong&gt;: The injector is configured to know which service implementations to inject into which clients.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inject Dependencies&lt;/strong&gt;: When a client is instantiated, the injector supplies it with the required service implementations based on the configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Dependency Injection Diagram&lt;/h3&gt;
&lt;p&gt;The following diagram illustrates the basic concept of dependency injection:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-05/dependency-injection-diagram.png&quot; alt=&quot;Dependency Injection Diagram&quot;/&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Client&lt;/strong&gt; requires a service interface to perform its function.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Dependency Injector&lt;/strong&gt; decides which implementation of the service interface (&lt;code&gt;Service A&lt;/code&gt; or &lt;code&gt;Service B&lt;/code&gt;) to inject into the client at runtime.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service A&lt;/strong&gt; and &lt;strong&gt;Service B&lt;/strong&gt; are different implementations of the same service interface. The injector injects one of these into the client based on the configuration or conditions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This pattern allows for high flexibility and decoupling of components within software applications, facilitating easier management, testing, and evolution of the application code.&lt;/p&gt;
&lt;h2&gt;How Can Dependency Injection Be Applied in Elixir?&lt;/h2&gt;
&lt;p&gt;As we mentioned earlier, dependency injection is a pattern that is more commonly associated with object-oriented programming languages. Functional programming languages like Elixir offer a different set of tools and idioms for managing dependencies and state. However, the principles of DI can still be applied in Elixir to achieve similar benefits.&lt;/p&gt;
&lt;p&gt;In Elixir, the emphasis on explicit over implicit dependency management aligns well with DI principles. For testing purposes, DI allows developers to easily replace real implementations with mocks or stubs, facilitating isolated unit tests that are not dependent on external services or state. This approach enhances test reliability and execution speed, as tests become less brittle and more focused on the functionality being tested.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Practical Application of Dependency Injection in Elixir for Testing&lt;/h3&gt;
&lt;p&gt;let&amp;#39;s look at how we can use dependency injection to inject mocks and configure dependencies in Elixir.&lt;/p&gt;
&lt;h4&gt;Injecting Mocks&lt;/h4&gt;
&lt;p&gt;One common application of DI in Elixir testing involves injecting mock modules or functions that simulate the behavior of real dependencies. This technique is particularly useful when dealing with external services like databases or APIs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.MyModule do
  def fetch_data(dataSource) do
    dataSource.query()
  end
end

defmodule MyApp.MyModuleTest do
  use ExUnit.Case

  test &amp;quot;fetch_data returns expected result&amp;quot; do
    mockDataSource = %{
      query: fn -&amp;gt; {:ok, &amp;quot;mocked data&amp;quot;} end
    }

    assert MyApp.MyModule.fetch_data(mockDataSource) == {:ok, &amp;quot;mocked data&amp;quot;}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;MyApp.MyModule.fetch_data/1&lt;/code&gt; depends on a &lt;code&gt;dataSource&lt;/code&gt; that responds to a &lt;code&gt;query&lt;/code&gt; function. During tests, a mock &lt;code&gt;dataSource&lt;/code&gt; is injected, allowing the test to run independently of any external data sources.&lt;/p&gt;
&lt;h4&gt;Configurable Dependencies&lt;/h4&gt;
&lt;p&gt;Another DI strategy involves using application configuration to define dependencies, which can then be overridden in the test environment.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/config.exs
config :my_app, data_service: MyApp.DataService

# config/test.exs
config :my_app, data_service: MyApp.MockDataService
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your application code, you would fetch the dependency from the application configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.MyModule do
  def fetch_data do
    dataSource = Application.get_env(:my_app, :data_service)
    dataSource.query()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This simple example shows how DI can be achieved in Elixir by configuring dependencies at runtime, allowing for easy substitution of real implementations with mocks or stubs during testing.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s review a more practical example that uses DI to inject a mock service into a module for testing.&lt;/p&gt;
&lt;h2&gt;Testing with Dependency Injection&lt;/h2&gt;
&lt;p&gt;In this example, we will work on &lt;code&gt;EmailScanner&lt;/code&gt;, a module that scans emails for spam. We will use a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if emails are spam and dependency injection to inject a mock &lt;code&gt;SpamFilterService&lt;/code&gt; for testing.&lt;/p&gt;
&lt;p&gt;Start by creating a new Elixir project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix new email_scanner
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s move on to implementation and testing.&lt;/p&gt;
&lt;h3&gt;Implementation with &lt;code&gt;ExUnit&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;First, create the &lt;code&gt;EmailScanner&lt;/code&gt; module. This module will depend on a &lt;code&gt;SpamFilterService&lt;/code&gt; to check if emails are spam. In this case, the &lt;code&gt;SpamFilterService&lt;/code&gt; will be injected as a dependency, making it easy to swap with a mock during testing.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScanner do
  def scan_email(spam_filter_service, email) do
    spam_filter_service.check_spam(email)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Testing &lt;code&gt;EmailScanner&lt;/code&gt; with &lt;code&gt;ExUnit&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Now, let&amp;#39;s write a test for the &lt;code&gt;EmailScanner&lt;/code&gt; module using &lt;code&gt;ExUnit&lt;/code&gt;. We&amp;#39;ll create a mock &lt;code&gt;SpamFilterService&lt;/code&gt; to inject during tests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MockSpamFilterService do
  def check_spam(_email), do: false
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this mock, the &lt;code&gt;check_spam/1&lt;/code&gt; function always returns &lt;code&gt;false&lt;/code&gt;, simulating a non-spam email. Next, let&amp;#39;s create a test case that makes use of our new mock:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EmailScannerTest do
  use ExUnit.Case

  test &amp;quot;scan_email with non-spam email returns false&amp;quot; do
    non_spam_email = %Email{content: &amp;quot;Hello, world!&amp;quot;}
    assert false == EmailScanner.scan_email(MockSpamFilterService, non_spam_email)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This test injects &lt;code&gt;MockSpamFilterService&lt;/code&gt; into &lt;code&gt;EmailScanner&lt;/code&gt;, isolating the test from the real spam filtering logic and focusing solely on the &lt;code&gt;EmailScanner&lt;/code&gt;&amp;#39;s behavior.&lt;/p&gt;
&lt;p&gt;By doing this, we can decouple the &lt;code&gt;EmailScanner&lt;/code&gt; module from the &lt;code&gt;SpamFilterService&lt;/code&gt;, making it easier to test and maintain.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve taken a look at using &lt;code&gt;ExUnit&lt;/code&gt; and testing, let&amp;#39;s turn to some common dependency injection mistakes to avoid and best practices.&lt;/p&gt;
&lt;h2&gt;Common Dependency Injection Pitfalls and Best Practices&lt;/h2&gt;
&lt;p&gt;First, we&amp;#39;ll touch on some pitfalls:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Over-Reliance on Mocks&lt;/strong&gt;: While DI makes it easy to replace real implementations with mocks, overusing mocks can lead to fragile tests that are overly focused on implementation details rather than behavior.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complex Dependency Graphs&lt;/strong&gt;: Introducing DI without careful planning can lead to a tangled web of dependencies that are hard to manage and understand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ignoring the Complexity of Configuration&lt;/strong&gt;: DI often requires some form of configuration to wire up dependencies. This configuration can become complex and unwieldy if not managed properly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To help you avoid these pitfalls, here are some best practices to follow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Define Clear Interfaces&lt;/strong&gt;: Ensure that your dependencies have clearly defined interfaces.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Configuration Wisely&lt;/strong&gt;: Be mindful of the complexity that configuration can introduce.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Leverage Elixir’s Capabilities&lt;/strong&gt;: Take advantage of Elixir’s features, such as module attributes and configuration files, to manage your dependencies effectively.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test with Real Implementations When Possible&lt;/strong&gt;: While mocking is useful, also test with real implementations to ensure that your system works as expected in real-world scenarios.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;#39;s it for this part of the series!&lt;/p&gt;
&lt;h2&gt;Wrapping Up and What&amp;#39;s Next&lt;/h2&gt;
&lt;p&gt;In this article, we have covered the basic concepts of dependency injection, its application in Elixir, and how it can be leveraged for testing. We have also discussed common pitfalls to avoid and best practices to follow when implementing DI in Elixir.&lt;/p&gt;
&lt;p&gt;In the next and final part of this series, we&amp;#39;ll look specifically at advanced dependency injection in Elixir using Rewire.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Deep Diving Into the Erlang Scheduler</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/04/23/deep-diving-into-the-erlang-scheduler.html"/>
    <id>https://blog.appsignal.com/2024/04/23/deep-diving-into-the-erlang-scheduler.html</id>
    <published>2024-04-23T00:00:00+00:00</published>
    <updated>2024-04-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s see how Erlang&#039;s scheduler works internally and dissect some of its key components.</summary>
    <content type="html">&lt;p&gt;Erlang is renowned for its remarkable fault tolerance and high concurrency. Erlang&amp;#39;s scheduler efficiently handles many lightweight processes.
The scheduler plays a crucial role in managing processes, concurrency, and system resources, efficiently coordinating these elements to help Erlang maintain fault tolerance and support high levels of concurrency in its applications.&lt;/p&gt;
&lt;p&gt;This post will dissect some of the scheduler&amp;#39;s key components and shed light on how it works internally.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Processes in Erlang&lt;/h2&gt;
&lt;p&gt;Erlang processes are lightweight, independent units of execution managed by the Erlang runtime system.
They are created and scheduled by the Erlang virtual machine (BEAM), and each Erlang process has its own memory space.
These should not be confused with operating system processes or threads.&lt;/p&gt;
&lt;p&gt;OS processes are entities managed by the OS and typically have more overhead in terms of memory and resources, as well as inter-process communication.
While threads are lighter than OS processes, they are still heavier than a typical Erlang process and share a common memory space within a process. Communication is usually easier between threads of the same process but still requires synchronization mechanisms.&lt;/p&gt;
&lt;p&gt;On the other hand, the Erlang VM (BEAM) is capable of spawning several lightweight processes with independent memory space and can communicate easily using message passing.
The scheduler inside the VM manages processes, allocates resources to processes, and context-switches between them.&lt;/p&gt;
&lt;h2&gt;Erlang Scheduler Architecture — Preemptive Scheduling&lt;/h2&gt;
&lt;p&gt;In a single-core setup, only one process can occupy the CPU core at any given time.
To emulate a concurrent system, the scheduler employs a preemptive, priority-based scheduling mechanism (don&amp;#39;t worry, we will explore what this means soon) that rapidly switches between available processes to create the illusion that all processes are executing simultaneously.
The Erlang Virtual Machine (BEAM) schedules processes to run sequentially, with one process running for a duration, being suspended, and then allowing another process to take its turn.
This process management strategy is characteristic of concurrency and does not entail true parallelism (which is not possible on a single-core system).
Tasks appear to run concurrently due to fast context switching, although they actually execute sequentially on a single core.&lt;/p&gt;
&lt;p&gt;To identify processes for potential swapping, Erlang introduces the concept of &amp;quot;reductions&amp;quot;. In Erlang, a reduction represents a unit of work performed by BEAM, encompassing fundamental operations such as function application, arithmetic calculations, or message passing.
The scheduler keeps track of the reductions executed by each process, preempting a process when it reaches a certain reduction count, thereby allowing another process to run.&lt;/p&gt;
&lt;h3&gt;Reductions&lt;/h3&gt;
&lt;p&gt;The idea of &amp;quot;reduction&amp;quot; in Erlang is inherited from its Prolog ancestry.
In Prolog, every execution step is termed a goal-reduction, involving breaking down a logic problem into individual components and solving each part accordingly.&lt;/p&gt;
&lt;p&gt;To promote fairness among processes, Erlang&amp;#39;s preemptive scheduling relies on reductions rather than time slices.
If a process exhausts its allocated reductions, it can be preempted, even if its execution isn&amp;#39;t complete.
This approach prevents a single process from monopolizing the CPU for an extended period, fostering fairness among concurrent processes.
By using reductions as the foundation for preemption, Erlang mitigates the risk of processes starving for CPU time.
This design ensures that every process, irrespective of its workload, is periodically allowed to execute.&lt;/p&gt;
&lt;p&gt;Moreover, reductions are flexibly applied based on the type of operation a process is performing.
For example, certain operations, such as I/O operations, may consume various reductions.
This adaptability allows the scheduler to effectively handle different types of operations.&lt;/p&gt;
&lt;p&gt;In other languages, traditional blocking I/O operations can lead to inefficient resource utilization, as threads might be blocked while waiting for I/O to complete.
Erlang&amp;#39;s asynchronous and non-blocking I/O model allows processes to continue executing other tasks while waiting for I/O operations to complete.
This minimizes the impact of blocking operations on overall system performance.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Priority&lt;/h3&gt;
&lt;p&gt;Each process in Erlang can have a &lt;code&gt;priority&lt;/code&gt; value that decides how often the scheduler will execute that process.
A process priority can be set using the &lt;code&gt;Process.flag/2&lt;/code&gt; (or &lt;a href=&quot;https://www.erlang.org/doc/man/erlang.html#process_flag-2&quot;&gt;process_flag/2&lt;/a&gt; on Erlang) function call:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Process.spawn(
  fn -&amp;gt;
    Process.flag(:priority, :high)
    # ...
  end,
  [:link]
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are 4 priority levels: &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;normal&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, and &lt;code&gt;max&lt;/code&gt;.
&lt;code&gt;max&lt;/code&gt; is reserved for internal use in Erlang and should not be used in application code.
Processes on each priority level get a separate run queue and are scheduled in the normal round-robin fashion as described above.&lt;/p&gt;
&lt;p&gt;Except &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;normal&lt;/code&gt;, Erlang executes the processes of each priority queue exclusively.
This means that if there is a process in the &lt;code&gt;max&lt;/code&gt; priority queue, only &lt;code&gt;max&lt;/code&gt; priority processes will be executed, and all other processes will be blocked.
Similarly, if there is a process in the &lt;code&gt;high&lt;/code&gt; priority queue, &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;normal&lt;/code&gt; processes will not be executed until all processes from the &lt;code&gt;high&lt;/code&gt; priority queue are executed (or are non-runnable).
&lt;code&gt;low&lt;/code&gt; and &lt;code&gt;normal&lt;/code&gt; queues behave slightly differently — the processes inside both queues are interleaved such that &lt;code&gt;normal&lt;/code&gt; priority processes are executed more often than &lt;code&gt;low&lt;/code&gt; priority ones, but &lt;code&gt;normal&lt;/code&gt; processes &lt;strong&gt;do not&lt;/strong&gt; block the execution of &lt;code&gt;low&lt;/code&gt; priority processes.&lt;/p&gt;
&lt;p&gt;Due to the blocking behavior of &lt;code&gt;high&lt;/code&gt; priority processes, they should be used very rarely and only for short-lived tasks.
Overusing &lt;code&gt;high&lt;/code&gt; priority processes is bound to lead to outages and affect the responsiveness of an application, as all other regular OTP processes run on &lt;code&gt;normal&lt;/code&gt; priority.&lt;/p&gt;
&lt;p&gt;Another point that&amp;#39;s important here is that Erlang places no restrictions on communication between different priority levels of processes.
So a high-priority process can wait for a message from a lower-priority process.
This is allowed, but will effectively lower the priority of the high-priority process.&lt;/p&gt;
&lt;h2&gt;Running on Multiple Cores&lt;/h2&gt;
&lt;p&gt;Up to this point, we&amp;#39;ve explored how the scheduler orchestrates processes within a single-core system.
However, in a multi-core environment, where additional resources are available for parallel processing, the Erlang VM creates a dedicated &amp;quot;run queue&amp;quot; for each available core.
This enables true parallelism, as multiple processes can run simultaneously (one on each available core).
Within each run queue, all processes adhere to the preemptive scheduling mechanism we discussed earlier.&lt;/p&gt;
&lt;p&gt;Typically, Erlang processes share the same run queue as their parent process, and a work-stealing algorithm may come into play to ensure load balancing.
For instance, if there are two cores in the system and one consistently handles busy processes while the other remains relatively idle, the Erlang schedulers on both cores engage in periodic communication.
This communication facilitates the movement of processes from the heavily loaded core to the less busy one, ensuring a more equitable distribution of workloads across both cores.&lt;/p&gt;
&lt;p&gt;In the broader context, beyond Erlang&amp;#39;s internal run queues, the operating system plays a role in managing the scheduling of threads onto OS-level cores.
This implies that processes not only experience swapping within the Erlang run queue but also may undergo a complete context switch or be moved to a different core at the OS level.&lt;/p&gt;
&lt;p&gt;Note that, because of the concept of work-stealing inside the Erlang VM, it is usually beneficial to run a single Erlang application instance on multiple cores rather than running separate instances of the same application on different cores of the same machine.
In a single instance, the schedulers dedicated to each core can better communicate between them to share the load equitably compared to a multi-node cluster where schedulers cannot share process load (even if all of that cluster&amp;#39;s nodes are on the same physical machine).&lt;/p&gt;
&lt;h2&gt;Performance and Optimization&lt;/h2&gt;
&lt;p&gt;Erlang&amp;#39;s scheduler takes out most of the complexities involved in building a concurrent system.
It automatically frees the developer from having to think about things like lock contention, thread overhead, and load balancing by handling these issues out of the box with its preemptive scheduling algorithm.&lt;/p&gt;
&lt;p&gt;Erlang provides various scheduler-related parameters that can be tuned for optimal performance.
Parameters like &lt;a href=&quot;https://www.erlang.org/doc/man/erl#+S&quot;&gt;+S&lt;/a&gt; (scheduler count) and &lt;a href=&quot;https://www.erlang.org/doc/man/erl#+P&quot;&gt;+P&lt;/a&gt; (maximum number of processes) allow you to configure the number of scheduler threads and processes.&lt;/p&gt;
&lt;p&gt;For example, you can start Erlang with &lt;code&gt;erl +S Schedulers:SchedulerOnline&lt;/code&gt; to control the number of scheduler threads.
By default, Erlang uses the number of CPU cores to identify these values automatically.
Note that while both &lt;code&gt;Scheduler&lt;/code&gt; and &lt;code&gt;SchedulerOnline&lt;/code&gt; accept values up to 1024, starting more schedulers than the number of CPU cores does not have any positive benefits for an app.&lt;/p&gt;
&lt;p&gt;Another possible step to fine-tune performance is to control the priorities of processes, as we&amp;#39;ve discussed.
It is indeed possible to execute certain high-priority tasks in Erlang.&lt;/p&gt;
&lt;p&gt;Nevertheless, this comes with an inherent risk of potentially rendering a system unresponsive and increasing latency, as processes with a high priority may block all other normal/low-priority processes.
Conversely, marking tasks identified as intentionally low priority can be advantageous to prioritize other processes above them.&lt;/p&gt;
&lt;p&gt;So be careful and use your judgment.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we&amp;#39;ve seen that the Erlang scheduler stands as a cornerstone in Erlang&amp;#39;s architecture, fostering fault tolerance, concurrency, and adaptability.
Its preemptive and dynamic nature equips developers to build resilient, highly concurrent systems capable of handling failures and utilizing resources optimally.
Understanding the intricacies of the Erlang scheduler can empower you to craft scalable and robust distributed applications.&lt;/p&gt;
&lt;p&gt;If you are interested in learning more about the scheduler, I recommend checking out the &lt;a href=&quot;https://blog.stenmans.org/theBeamBook/#CH-Scheduling&quot;&gt;Scheduling chapter in The BEAM Book&lt;/a&gt; and &lt;a href=&quot;https://www.erlang.org/docs/23/efficiency_guide/processes&quot;&gt;Processes from the Erlang Efficiency Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&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;strong&gt;P.P.S. &lt;a href=&quot;https://www.appsignal.com/elixir/erlang-monitoring&quot;&gt;AppSignal has an integration for Erlang — check it out&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Use Flume in your Elixir Application</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/04/02/how-to-use-flume-in-your-elixir-app.html"/>
    <id>https://blog.appsignal.com/2024/04/02/how-to-use-flume-in-your-elixir-app.html</id>
    <published>2024-04-02T00:00:00+00:00</published>
    <updated>2024-04-02T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s learn how to handle background jobs in Elixir with Flume.</summary>
    <content type="html">&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&amp;#39;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=&quot;https://github.com/sorentwo/oban&quot;&gt;Oban&lt;/a&gt;, backed by PostgreSQL or SQLite, also provides a queue-based job processing system.
&lt;a href=&quot;https://github.com/akira/exq&quot;&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&amp;#39;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=&quot;https://hexdocs.pm/elixir/1.16.0/GenServer.html&quot;&gt;GenServer&lt;/a&gt;, &lt;a href=&quot;https://hexdocs.pm/elixir/1.16.0/Task.html&quot;&gt;Task&lt;/a&gt;, and &lt;a href=&quot;https://hexdocs.pm/elixir/1.16.0/Supervisor.html&quot;&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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def deps do
  [
    {:flume, github: &amp;quot;scripbox/flume&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Application do
  use Application

  import Supervisor.Spec

  @impl true
  def start(_type, _args) do
    Supervisor.start_link([
      # ...
      # Start Flume supervisor
      supervisor(Flume, []),
      #...
    ], strategy: :one_for_one, name: MyApp.Supervisor)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, configure it inside &lt;code&gt;config/config.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flume,
  name: Flume,
  # Redis config
  host: &amp;quot;127.0.0.1&amp;quot;,
  port: &amp;quot;6379&amp;quot;,
  namespace: &amp;quot;my-app&amp;quot;,
  database: 0,
  redis_pool_size: 10
&lt;/code&gt;&lt;/pre&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.
Let&amp;#39;s create one now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.OrdersWorker do
  def process(order_id) do
    # process the order
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Flume.enqueue(:default, MyApp.OrdersWorker, :process, [order_id])
&lt;/code&gt;&lt;/pre&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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flume, pipelines: [%{name: &amp;quot;default_pipeline&amp;quot;, queue: &amp;quot;default&amp;quot;}]
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flume, pipelines: [%{name: &amp;quot;default_pipeline&amp;quot;, queue: &amp;quot;default&amp;quot;, max_demand: 10}]
&lt;/code&gt;&lt;/pre&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;Banner lang=&quot;elixir&quot; /&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flume, pipelines: [%{
  name: &amp;quot;default_pipeline&amp;quot;,
  queue: &amp;quot;default&amp;quot;,
  rate_limit_count: 100,
  rate_limit_scale: 60 * 1000
}]
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flume, pipelines: [
  %{
    name: &amp;quot;email_pipeline&amp;quot;,
    queue: &amp;quot;email&amp;quot;,
    rate_limit_count: 100,
    rate_limit_scale: 60 * 1000
    rate_limit_key: &amp;quot;notifications&amp;quot;
  },
  %{
    name: &amp;quot;sms_pipeline&amp;quot;,
    queue: &amp;quot;sms&amp;quot;,
    rate_limit_count: 100,
    rate_limit_scale: 60 * 1000
    rate_limit_key: &amp;quot;notifications&amp;quot;
  }
]
&lt;/code&gt;&lt;/pre&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&amp;#39;t confuse this with the &lt;code&gt;max_demand&lt;/code&gt; parameter, which governs how many &amp;quot;concurrent&amp;quot; jobs can execute simultaneously.
Even with a low max demand, it&amp;#39;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&amp;#39;s also useful to define a batch size with a pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flume, pipelines: [%{
  name: &amp;quot;default_pipeline&amp;quot;,
  queue: &amp;quot;default&amp;quot;,
  max_demand: 10,
  batch_size: 5,
}]
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.OrdersWorker do
  def process(jobs) do
    # jobs contains up to 5 arrays containing arguments for each individual call:
    # [[order1_id], [order2_id], [order3_id], [order4_id], [order5_id]]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The application code determines how to manage these jobs.
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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Flume.pause_all(temporary: false, async: true)
&lt;/code&gt;&lt;/pre&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&amp;#39;s name.
It accepts the same options as &lt;code&gt;pause_all&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Flume.pause(&amp;quot;default_pipeline&amp;quot;, temporary: false, async: true)
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Flume.pause(&amp;quot;default_pipeline&amp;quot;, temporary: true, async: true)
&lt;/code&gt;&lt;/pre&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.
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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :flume,
  backoff_initial: 30_000,
  backoff_max: 36_00_000,
  max_retries: 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are several other configuration options to fine-tune Flume further.
Please refer to the &lt;a href=&quot;https://github.com/scripbox/flume?tab=readme-ov-file#usage&quot;&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.
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&amp;#39;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=&quot;https://hexdocs.pm/telemetry_metrics_appsignal/TelemetryMetricsAppsignal.html&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.FlumeConfigurator do
  @default_pipelines %{
    &amp;quot;default_pipeline&amp;quot; =&amp;gt; %{name: &amp;quot;default_pipeline&amp;quot;, queue: &amp;quot;default&amp;quot;},
    &amp;quot;notifications_pipeline&amp;quot; =&amp;gt; %{
      name: &amp;quot;notifications_pipeline&amp;quot;,
      queue: &amp;quot;notifications&amp;quot;,
      rate_limit_count: 100,
      rate_limit_scale: 60 * 1000
    },
    &amp;quot;video_transcoding_pipeline&amp;quot; =&amp;gt; %{name: &amp;quot;video_transcoding_pipeline&amp;quot;, queue: &amp;quot;video_transcoding&amp;quot;, max_demand: 5}
  }

  def flume_pipelines() do
    pipelines(System.get_env(&amp;quot;FLUME_PIPELINES&amp;quot;))
  end

  defp pipelines(nil), do: []

  defp pipelines(value) when is_binary(value) do
    value
    |&amp;gt; String.split(&amp;quot;,&amp;quot;, trim: true)
    |&amp;gt; Enum.map(fn name -&amp;gt; Map.fetch!(@default_pipelines, name) end)
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import MyApp.FlumeConfigurator, only: [flume_pipelines: 0]
config :flume, pipelines: flume_pipelines()
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;FLUME_PIPELINES=default_pipeline,notifications_pipeline,video_transcoding_pipeline /path/to/release start
&lt;/code&gt;&lt;/pre&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=&quot;https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Release.html&quot;&gt;&lt;code&gt;mix phx.gen.release&lt;/code&gt;&lt;/a&gt; task to prepare your Phoenix app for release:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;if System.get_env(&amp;quot;PHX_SERVER&amp;quot;) do
  config :pug_n_play_platform, PugNPlayPlatformWeb.Endpoint, server: true
end
&lt;/code&gt;&lt;/pre&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&amp;#39;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&amp;#39;s concurrency and fault tolerance but also gain a powerful ally for managing and optimizing your application&amp;#39;s background tasks.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Direct File Uploads to Amazon S3 with Phoenix LiveView</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/03/19/direct-file-uploads-to-amazon-s3-with-phoenix-liveview.html"/>
    <id>https://blog.appsignal.com/2024/03/19/direct-file-uploads-to-amazon-s3-with-phoenix-liveview.html</id>
    <published>2024-03-19T00:00:00+00:00</published>
    <updated>2024-03-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s explore how you can upload from Phoenix LiveView directly to Amazon S3.</summary>
    <content type="html">&lt;p&gt;In this post, we&amp;#39;ll add file upload capabilities to a Phoenix LiveView application and directly upload files to Amazon S3.&lt;/p&gt;
&lt;p&gt;Without further ado, let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Setting Up Our Phoenix LiveView Project&lt;/h2&gt;
&lt;p&gt;Our example will upload behavior to an existing application with a “create puppy” feature. We&amp;#39;re going to go through the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/uploads.html&quot;&gt;Phoenix LiveView Uploads guide&lt;/a&gt;, making small adjustments as we go.&lt;/p&gt;
&lt;p&gt;To begin, we need to set up our project. You can skip this step if you already have an existing Phoenix LiveView application. Otherwise, you can create a new project by running the following command in your terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix phx.new puppies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Change into the project directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd puppies
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And create a new Phoenix LiveView:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix phx.gen.live Puppies Puppy puppies name:string breed:string color:string photo_url: string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate the necessary files and migrations for our live view and model.&lt;/p&gt;
&lt;h2&gt;Allowing Uploads&lt;/h2&gt;
&lt;p&gt;The very first thing we need to do is enable an upload on mount. Open the form component file at &lt;code&gt;lib/puppies_web/live/puppy_live/form_component.ex&lt;/code&gt;. You will see an &lt;code&gt;update/2&lt;/code&gt; function where we will enable file uploads. Add the following line to your callback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;allow_upload(socket, :photo, accept: ~w(.png .jpeg .jpg .webp), max_entries: 1, auto_upload: true)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the &lt;code&gt;update/2&lt;/code&gt; callback ultimately looking like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@impl true
def update(%{puppy: puppy} = assigns, socket) do
  changeset = Puppies.change_puppy(puppy)

  {:ok,
   socket
   |&amp;gt; allow_upload(:photo, accept: ~w(.png .jpeg .jpg .webp), max_entries: 1, auto_upload: true, external: &amp;amp;presign_entry/2)
   |&amp;gt; assign(assigns)
   |&amp;gt; assign(:form, to_form(changeset)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This line enables file uploads for the &lt;code&gt;:photo&lt;/code&gt; attribute, accepting only JPEG, WEBP, and PNG file formats and only one upload at a time via &lt;code&gt;max_entries: 1&lt;/code&gt;. With &lt;code&gt;auto_upload: true&lt;/code&gt;, a photo begins uploading as soon as a user selects it in our form. You can modify these options based on your requirements by looking at the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#allow_upload/3&quot;&gt;&lt;code&gt;allow_upload&lt;/code&gt; function docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you’re not using a LiveComponent, you can add this line to your &lt;code&gt;mount/2&lt;/code&gt; callback.&lt;/strong&gt;&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Adding the Upload Markup&lt;/h2&gt;
&lt;p&gt;Next, we’re going to render the HTML elements in our form. This is where we will put our file input, a preview of our picture, and the upload percentage status. We&amp;#39;ll also add drag-and-drop support for images.&lt;/p&gt;
&lt;p&gt;To render the file upload form in our LiveView, we need to add the necessary HTML components. In the puppy form HTML, add all of these file upload goodies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;%= hidden_input @form, :photo_url %&amp;gt; &amp;lt;%= error_tag @form, :photo_url %&amp;gt;

  &amp;lt;div phx-drop-target=&amp;quot;{@uploads.photo.ref}&amp;quot;&amp;gt;
    &amp;lt;.live_file_input upload={@uploads.photo} /&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div&amp;gt;
    &amp;lt;%= for {_ref, msg} &amp;lt;- @uploads.photo.errors do %&amp;gt;
    &amp;lt;h3&amp;gt;&amp;lt;%= Phoenix.Naming.humanize(msg) %&amp;gt;&amp;lt;/h3&amp;gt;

    &amp;lt;% end %&amp;gt; &amp;lt;%= for entry &amp;lt;- @uploads.photo.entries do %&amp;gt; &amp;lt;.live_img_preview
    entry={entry} width=&amp;quot;75&amp;quot; /&amp;gt;
    &amp;lt;div class=&amp;quot;py-5&amp;quot;&amp;gt;&amp;lt;%= entry.progress %&amp;gt;%&amp;lt;/div&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this code, we render a file input with drag-and-drop support via the &lt;code&gt;phx-drop-target&lt;/code&gt; form binding and &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#live_file_input/1&quot;&gt;live_file_input&lt;/a&gt; component provided by Phoenix LiveView. We also display a live file preview of the uploaded photo with &lt;code&gt;&amp;lt;.live_img_preview entry={entry} width=&amp;quot;75&amp;quot; /&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Live updates to the preview, progress, and errors will occur as the end-user interacts with the file input.&lt;/p&gt;
&lt;p&gt;We render an image preview for each uploaded image stored in &lt;code&gt;@uploads.photo.entries&lt;/code&gt;. The &lt;code&gt;@uploads&lt;/code&gt; variable becomes available to us when we pipe into the &lt;code&gt;allow_upload/3&lt;/code&gt; function in our form component (remember, you can do this in the &lt;code&gt;mount/2&lt;/code&gt; callback for a LiveView if you aren’t using a LiveComponent).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;for {_ref, msg} &amp;lt;- @uploads.photo.errors&lt;/code&gt; will display any errors, like uploading the wrong file type, to the user.&lt;/p&gt;
&lt;p&gt;Finally, notice this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= hidden_input @form, :photo_url %&amp;gt;
&amp;lt;%= error_tag @form, :photo_url %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These appear in the form because after we upload the file to Amazon S3, we’re going to persist the url of the picture to the database.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important: Your LiveView upload form must implement both &lt;code&gt;phx-submit&lt;/code&gt; and &lt;code&gt;phx-change&lt;/code&gt; callbacks, even if you’re not using them.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The LiveView upload feature set will not work without these callbacks and subsequent &lt;code&gt;handle_event&lt;/code&gt; callbacks. &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/uploads.html#render-reactive-elements&quot;&gt;Read more about this&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Configuring Amazon S3 to Phoenix LiveView&lt;/h2&gt;
&lt;p&gt;Before we can test our file upload feature, we need to set up our Amazon S3 bucket and configuration. Setting up your Amazon S3 bucket and configuring access is outside the scope of this guide, but &lt;a href=&quot;https://www.youtube.com/watch?v=i2JXvgHsV9w&quot;&gt;this video should help&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Consuming the File Upload on the Back-end&lt;/h2&gt;
&lt;p&gt;We’re going to crack open the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/uploads-external.html#direct-to-s3&quot;&gt;Direct to S3 guide&lt;/a&gt; to bring all of this home.&lt;/p&gt;
&lt;p&gt;In our &lt;code&gt;allow_upload&lt;/code&gt; function call, add “external” support so that we can get it on Amazon S3. It should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def update(%{puppy: puppy} = assigns, socket) do
  changeset = Puppies.change_puppy(puppy)

  {:ok,
   socket
   |&amp;gt; allow_upload(:photo, accept: ~w(.png .jpeg .jpg .webp), max_entries: 1, auto_upload: true, external: &amp;amp;presign_entry/2)
   |&amp;gt; assign(assigns)
   |&amp;gt; assign(:changeset, changeset)}
end

defp presign_entry(entry, %{assigns: %{uploads: uploads}} = socket) do
  {:ok, SimpleS3Upload.meta(entry, uploads), socket}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;external: &amp;amp;presign_entry/2&lt;/code&gt; sends the file to our &lt;code&gt;presign_entry/2&lt;/code&gt; function. This function dedicates work to a &lt;code&gt;SimpleS3Upload&lt;/code&gt; module that generates a “presigned_url”. We need to upload files directly to Amazon S3 via our front-end safely, without exposing our Amazon S3 credentials.&lt;/p&gt;
&lt;p&gt;So, we generate a pre-authenticated short-term URL on the back-end with our Amazon credentials. We then send this URL back to the front-end, where it can safely upload our file to Amazon S3, already completely safely authenticated.&lt;/p&gt;
&lt;p&gt;You can find the &lt;a href=&quot;https://gist.github.com/plicjo/5e5ced381f2b71d69d98b3e48885aacf#file-simple_s3_upload-ex&quot;&gt;content of the SimpleS3Upload file here&lt;/a&gt;. It’s 170+ lines of code purely dedicated to creating a pre-signed url for pre-authenticated file uploading.&lt;/p&gt;
&lt;p&gt;Inside the &lt;code&gt;SimpleS3Upload&lt;/code&gt; module, you’ll see references to the configuration you need to add.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp config do
  %{
    region: region(),
    access_key_id: Application.fetch_env!(:puppies, :access_key_id),
    secret_access_key: Application.fetch_env!(:puppies, :secret_access_key)
  }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In your app, you’ll need to specify your secret keys/credentials in your &lt;code&gt;config/config.exs&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :puppies,
  access_key_id: System.fetch_env!(&amp;quot;AWS_ACCESS_KEY_ID&amp;quot;),
  secret_access_key: System.fetch_env!(&amp;quot;AWS_SECRET_ACCESS_KEY&amp;quot;),
  bucket: System.fetch_env!(&amp;quot;S3_BUCKET_NAME&amp;quot;),
  region: System.fetch_env!(&amp;quot;AWS_REGION&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s pull this through to the front-end!&lt;/p&gt;
&lt;h2&gt;Uploading the File to S3 on the Front-end&lt;/h2&gt;
&lt;p&gt;We now need to upload the file from our front-end JavaScript in &lt;code&gt;assets/js/app.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;let Uploaders = {}

Uploaders.S3 = function(entries, onViewError){
  entries.forEach(entry =&amp;gt; {
    let formData = new FormData()
    let {url, fields} = entry.meta
    Object.entries(fields).forEach(([key, val]) =&amp;gt; formData.append(key, val))
    formData.append(&amp;quot;file&amp;quot;, entry.file)
    let xhr = new XMLHttpRequest()
    onViewError(() =&amp;gt; xhr.abort())
    xhr.onload = () =&amp;gt; xhr.status === 204 ? entry.progress(100) : entry.error()
    xhr.onerror = () =&amp;gt; entry.error()
    xhr.upload.addEventListener(&amp;quot;progress&amp;quot;, (event) =&amp;gt; {
      if(event.lengthComputable){
        let percent = Math.round((event.loaded / event.total) * 100)
        if(percent &amp;lt; 100){ entry.progress(percent) }
      }
    })

    xhr.open(&amp;quot;POST&amp;quot;, url, true)
    xhr.send(formData)
  })
}

let liveSocket = new LiveSocket(&amp;quot;/live&amp;quot;, Socket, {
  uploaders: Uploaders,
  params: {_csrf_token: csrfToken}
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will upload each one of our files to Amazon S3 via AJAX.&lt;/p&gt;
&lt;p&gt;Notice how we have an event listener for a “progress” event, always keeping the upload status available via &lt;code&gt;entry.progress(percent)&lt;/code&gt;. Remember, we’re displaying the progress percentage in our HTML. And if there’s an error in the AJAX response, &lt;code&gt;entry.error()&lt;/code&gt; has us covered. We render any file upload errors back to the user in the HTML, too.&lt;/p&gt;
&lt;p&gt;The URL it’s uploading to is the pre-signed one that we generated on the back-end.&lt;/p&gt;
&lt;h2&gt;Saving the Amazon URL to the Database&lt;/h2&gt;
&lt;p&gt;In our form, there&amp;#39;s a form submit binding that looks like &lt;code&gt;phx_submit: &amp;quot;save&amp;quot;&lt;/code&gt;, meaning we have a matching &lt;code&gt;handle_event&lt;/code&gt; in our &lt;code&gt;LiveView/form_component&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Make the following change:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(&amp;quot;save&amp;quot;, %{&amp;quot;puppy&amp;quot; =&amp;gt; puppy_params}, socket) do
  puppy_params = put_photo_urls(socket, puppy_params)
  save_puppy(socket, socket.assigns.action, puppy_params)
end

defp put_photo_urls(socket, puppy) do
  uploaded_file_urls = consume_uploaded_entries(socket, :photo, fn _, entry -&amp;gt;
    {:ok, SimpleS3Upload.entry_url(entry)}
  end)

  %{puppy | &amp;quot;photo_url&amp;quot; =&amp;gt; add_photo_url_to_params(List.first(uploaded_file_urls), puppy[&amp;quot;photo_url&amp;quot;])}
end

defp add_photo_url_to_params(s3_url, photo_url) when is_nil(s3_url), do: photo_url
defp add_photo_url_to_params(s3_url, _photo_url), do: s3_url
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re not adding the Amazon S3 photo URL to &lt;code&gt;puppy_params&lt;/code&gt;. The &lt;code&gt;consume_uploaded_entries&lt;/code&gt; function call is where this magic is happening.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SimpleS3Upload.entry_url(entry)&lt;/code&gt; is the dynamically generated URL where our image lives in our S3 bucket.&lt;/p&gt;
&lt;p&gt;Notably, observe my pattern matching in the &lt;code&gt;add_photo_url_to_params&lt;/code&gt; function. This guards us from overwriting the puppy with a blank URL if we don’t upload a file when updating the puppy’s attributes.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the final result:&lt;/p&gt;
&lt;Video fileName=&quot;/images/blog/2024-03/final-result-puppy&quot; /&gt;

&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;You now know how to upload from Phoenix LiveView directly to Amazon S3.&lt;/p&gt;
&lt;p&gt;We began by enabling file uploads in our LiveView and adding the necessary components to our HTML template. We then created a pre-signed (pre-authenticated) URL to upload the file to with the &lt;code&gt;SimpleS3Upload&lt;/code&gt; module. Next, we actually performed the file upload via AJAX calls by adding the uploader to our application’s JavaScript. Finally, we consumed the files we uploaded, persisting the URL to the database.&lt;/p&gt;
&lt;p&gt;Have fun experimenting with this feature and enhancing your application!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Powerful Caching in Elixir with Cachex</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/03/05/powerful-caching-in-elixir-with-cachex.html"/>
    <id>https://blog.appsignal.com/2024/03/05/powerful-caching-in-elixir-with-cachex.html</id>
    <published>2024-03-05T00:00:00+00:00</published>
    <updated>2024-03-05T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Improve the performance of your Elixir application with Cachex, a powerful caching library.</summary>
    <content type="html">&lt;p&gt;Developers often initially look to the Elixir language and stack because it&amp;#39;s known for being able to handle massive amounts of concurrent requests and scale easily. This makes Elixir a great choice for building highly performant applications.&lt;/p&gt;
&lt;p&gt;However, sometimes operations are computationally expensive and can slow down your application. This is where caching comes in.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll explore how Cachex, a powerful library tailored for Elixir, can help you add caching to your application and improve its performance.&lt;/p&gt;
&lt;h2&gt;Understanding Caching and Its Importance in Elixir&lt;/h2&gt;
&lt;p&gt;Caching is the art of storing data temporarily to reduce redundancy and improve access times. The primary benefits of caching include faster data retrieval, reduced load on primary data sources, and enhanced application responsiveness. However, caching is not without its drawbacks. Over-reliance can lead to stale data, and improper cache management can result in increased complexity.&lt;/p&gt;
&lt;p&gt;Caching can be added to reduce bottlenecks and improve performance in Elixir: for example, when dealing with external systems, databases, or computationally expensive operations. Caching can also be used to store frequently accessed data in memory, such as user sessions or application state.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s take a quick look at some benefits and disadvantages of caching.&lt;/p&gt;
&lt;h3&gt;Benefits of Caching&lt;/h3&gt;
&lt;p&gt;Caching comes with several benefits, including:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Improved performance&lt;/strong&gt;: Caching can significantly reduce data retrieval times, making applications more responsive.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced load on primary data sources&lt;/strong&gt;: By serving data from a cache, there&amp;#39;s less strain on primary data sources like databases, reducing the risk of them becoming a bottleneck.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost savings&lt;/strong&gt;: Reducing the number of calls to external services or databases can lead to cost savings, especially if those calls are billable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enhanced user experience&lt;/strong&gt;: Faster response times lead to a smoother user experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Caching can help applications handle more users simultaneously by reducing the need for resource-intensive operations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduced network traffic&lt;/strong&gt;: Serving data from the cache can reduce the amount of data that needs to be transmitted over a network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Offline access&lt;/strong&gt;: In some scenarios, caching allows users to access certain pieces of data even when offline.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Drawbacks of Caching&lt;/h3&gt;
&lt;p&gt;Even though there are a lot of benefits to caching, there are some drawbacks you should be mindful of:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Stale data&lt;/strong&gt;: Cached data can become outdated, leading to users receiving old or incorrect information.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Increased complexity&lt;/strong&gt;: Implementing caching introduces another layer of complexity to system architecture and can complicate debugging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory usage&lt;/strong&gt;: Caching, especially when done extensively, can consume a significant amount of memory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache invalidation&lt;/strong&gt;: Deciding when and how to invalidate or refresh the cache can be challenging.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache warm-up&lt;/strong&gt;: After a cache clear or system restart, the cache might be &amp;quot;cold&amp;quot; and it can take time to &amp;quot;warm up&amp;quot; to an optimal state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Potential for cache thrashing&lt;/strong&gt;: Rapidly adding and evicting items can lead to cache thrashing, where the cache doesn&amp;#39;t provide its benefits effectively.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintenance overhead&lt;/strong&gt;: Over time, your caching strategy might need adjustments, leading to additional maintenance work.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It&amp;#39;s worth noting that while caching offers numerous advantages, it&amp;#39;s essential to implement it judiciously, considering the specific needs and characteristics of each application.&lt;/p&gt;
&lt;h3&gt;Caching Options in Elixir&lt;/h3&gt;
&lt;p&gt;In the world of Elixir, many different options are available for caching. It is important to understand that each library has its own set of pros and cons. As developers, we need to consider the specific scenario where we intend to use caching and choose the right tool for the job.&lt;/p&gt;
&lt;p&gt;Some of the options available to use are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cachex&lt;/strong&gt;: A powerful caching library tailored for Elixir. It offers features like Time-to-Live (TTL), fallbacks, and locking mechanisms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ConCache&lt;/strong&gt;: A concurrent caching library for Elixir. It&amp;#39;s built on top of Erlang Term Storage (ETS) and provides features like TTL and cache partitioning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nebulex&lt;/strong&gt;: A flexible and highly configurable caching library. It supports different caching strategies and has built-in support for distributed caching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Erlang Term Storage (ETS)&lt;/strong&gt;: While not exclusively a caching solution, ETS is an in-memory store that&amp;#39;s often used for caching in Elixir applications. It&amp;#39;s a core feature of the Erlang runtime system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mnesia&lt;/strong&gt;: A distributed database management system that comes with Erlang/OTP. It can be used for caching, especially in distributed Elixir applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redis via Redix&lt;/strong&gt;: While Redis is not an Elixir-specific solution, it&amp;#39;s a popular choice for caching in many applications. The Redix library allows Elixir applications to interact with Redis easily.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Least Recently Used (LRU) caches&lt;/strong&gt;: There are several Elixir libraries, like &lt;code&gt;lru_cache&lt;/code&gt;, that implement the LRU caching algorithm.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the rest of this article, we&amp;#39;ll focus on Cachex, because it&amp;#39;s a robust caching solution that&amp;#39;s easy to use and offers a wide range of features. It&amp;#39;s also well-documented and has a vibrant community around it.&lt;/p&gt;
&lt;h2&gt;Introduction to Cachex for Elixir&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/cachex/Cachex.html&quot;&gt;Cachex&lt;/a&gt; offers a suite of features that make it an indispensable tool for Elixir developers. From simple key-value storage to advanced features like TTL settings and fallback mechanisms, Cachex provides a comprehensive caching solution.&lt;/p&gt;
&lt;p&gt;Among the many features that make Cachex a powerful tool for caching in Elixir, the following stand out:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt;: Cachex is designed for high performance, ensuring rapid data retrieval and insertion. This is crucial for applications that require real-time responsiveness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrency support&lt;/strong&gt;: Elixir is known for its concurrency capabilities, and Cachex is built to handle concurrent operations seamlessly. It ensures that multiple processes can interact with the cache without causing data inconsistencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced features&lt;/strong&gt;, including &lt;strong&gt;TTL&lt;/strong&gt; (allowing developers to specify how long an item should remain in the cache, to ensure that data doesn&amp;#39;t become stale), &lt;strong&gt;fallbacks&lt;/strong&gt; (mechanisms to compute values if they&amp;#39;re missing from the cache, so that an application can still function even if a cache miss occurs), and &lt;strong&gt;locking mechanisms&lt;/strong&gt; (ensuring data integrity during operations like cache updates).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexibility&lt;/strong&gt;: Cachex is not just a simple key-value store. It supports complex data structures, making it versatile for a range of applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distributed caching&lt;/strong&gt;: While Cachex primarily operates as a local cache, it can be combined with other tools and libraries to support distributed caching scenarios, making it suitable for clustered Elixir applications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comprehensive documentation&lt;/strong&gt;: Cachex comes with extensive documentation, making it easier for developers to get started and harness its full potential.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration with Telemetry&lt;/strong&gt;: Cachex integrates with the Telemetry library, allowing developers to gather metrics and monitor cache performance in real-time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache eviction strategies&lt;/strong&gt;: Cachex supports various cache eviction strategies, such as LRU, ensuring that the cache remains efficient even as it fills up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault tolerance&lt;/strong&gt;: Built with Elixir&amp;#39;s fault-tolerant nature in mind, failures are isolated and don&amp;#39;t bring down the entire application.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Adding Caching to Your Elixir Application with Cachex&lt;/h2&gt;
&lt;p&gt;To get started with Cachex, we&amp;#39;ll need to add it as a dependency to our project.&lt;/p&gt;
&lt;p&gt;To install Cachex in an Elixir application, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Add cachex as a dependency&lt;/strong&gt;:
Open your &lt;code&gt;mix.exs&lt;/code&gt; file and add &lt;code&gt;:cachex&lt;/code&gt; to the list of dependencies:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
 [
   {:cachex, &amp;quot;~&amp;gt; 3.3&amp;quot;} # The version number might change over time, so always check for the latest version.
   ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Fetch and compile dependencies&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Run the following command in your terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will fetch and compile the Cachex library along with any of its dependencies.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;strong&gt;Start Cachex&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before using Cachex in your application, you need to start it. You can start a new cache instance with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:ok, _} = Cachex.start_link(:my_cache)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;:my_cache&lt;/code&gt; is the name of the cache. You can choose any name that suits your application.&lt;/p&gt;
&lt;p&gt;Calling &lt;code&gt;Cachex.start_link/1&lt;/code&gt; will start a new cache instance with the default configuration. If you want to customize the configuration, you can pass in a map with the desired configuration options.&lt;/p&gt;
&lt;p&gt;For example, if you want to set the cache size to 1000 items, you can do so by passing in the &lt;code&gt;:size&lt;/code&gt; option:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:ok, _} = Cachex.start_link(:my_cache, %{size: 1000})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s important to note that Cachex is built on top of GenServer, so you can use the same techniques to start and supervise it.&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;Add to application supervision tree&lt;/strong&gt;:
If you want the cache to be supervised and automatically restart in case of failures, you can add it to your application&amp;#39;s supervision tree. This ensures that the cache is always available throughout the lifecycle of your application.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In your application&amp;#39;s supervisor, you can add:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;children = [
 {Cachex, name: :my_cache}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will start the Cachex cache when your application starts and supervise it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; There are some scenarios where you might not want to start Cachex automatically. For example, if you&amp;#39;re using Cachex in a Phoenix application, you might want to start it only when the application is running in production. In such cases, you can start Cachex manually in your application&amp;#39;s supervision tree.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s it! You&amp;#39;ve successfully installed Cachex in your Elixir application. You can now use its various functions to cache data, retrieve cached data, and manage your cache. Always refer to the &lt;a href=&quot;https://hexdocs.pm/cachex/getting-started.html&quot;&gt;official Cachex documentation&lt;/a&gt; for more detailed information and best practices.&lt;/p&gt;
&lt;h3&gt;Working with Phoenix&lt;/h3&gt;
&lt;p&gt;A common use case for Cachex is to cache data in a Phoenix application. Phoenix doesn&amp;#39;t have a built-in caching mechanism, so developers often turn to third-party libraries like Cachex.&lt;/p&gt;
&lt;p&gt;Before we can use Cachex in a Phoenix application, we need to add it as a dependency and initialize it. We can do this by following the steps outlined in the previous section.&lt;/p&gt;
&lt;p&gt;Once Cachex is installed, we can use it in our Phoenix application. Let&amp;#39;s look at a few examples of using Cachex in a Phoenix application.&lt;/p&gt;
&lt;h4&gt;Caching Database Queries&lt;/h4&gt;
&lt;p&gt;One common use case in Phoenix applications is to cache the results of database queries to reduce database load and speed up data retrieval. After fetching data from the database, you can store it in the Cachex cache:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def get_user(id) do
  case Cachex.get(:my_cache, id) do
    {:ok, nil} -&amp;gt;
      user = Repo.get(User, id)
      Cachex.put(:my_cache, id, user)
      user
    {:ok, user} -&amp;gt; user
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function &lt;code&gt;get_user/1&lt;/code&gt; retrieves a user by their id. It first checks if the user is available in the cache, and if not, it fetches them from a repository (likely a database) and then caches the result for future calls. Let&amp;#39;s break down what&amp;#39;s happening here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Function definition&lt;/strong&gt;: The function &lt;code&gt;get_user/1&lt;/code&gt; is defined to accept a single argument, &lt;code&gt;id&lt;/code&gt;, which identifies a user.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache lookup&lt;/strong&gt;: The function starts by trying to retrieve the user from a cache named &lt;code&gt;:my_cache&lt;/code&gt; using the provided id as the cache key. &lt;code&gt;Cachex.get(:my_cache, id)&lt;/code&gt; attempts to get the value associated with the key id from &lt;code&gt;:my_cache&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling cache results&lt;/strong&gt;: The result of the cache lookup is pattern-matched using a case statement to determine the next steps.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cache miss &lt;code&gt;{:ok, nil}&lt;/code&gt;&lt;/strong&gt;: If the cache returns &lt;code&gt;{:ok, nil}&lt;/code&gt;, it indicates a cache miss, meaning the user is not present in the cache.&lt;ul&gt;
&lt;li&gt;The function then fetches the user from a repository using &lt;code&gt;Repo.get(User, id)&lt;/code&gt;. This is likely a call to a database to retrieve the user data.&lt;/li&gt;
&lt;li&gt;Once the user data is fetched, it&amp;#39;s stored in the cache using &lt;code&gt;Cachex.put(:my_cache, id, user)&lt;/code&gt;. This ensures that subsequent calls for the same user id will find the user in the cache and won&amp;#39;t need to hit the database.&lt;/li&gt;
&lt;li&gt;Finally, the fetched user data is returned as the result of the function.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache hit &lt;code&gt;{:ok, user}&lt;/code&gt;&lt;/strong&gt;: If the cache returns &lt;code&gt;{:ok, user}&lt;/code&gt; where the user is not nil, this is a cache hit. The user data has been found in the cache. The function simply returns the cached user data without making any database calls.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Caching Views&lt;/h4&gt;
&lt;p&gt;Sometimes, we might need to cache rendered views to improve performance. For example, if we have a view that&amp;#39;s expensive to render, we can cache it to reduce the load on the server and speed up data retrieval.&lt;/p&gt;
&lt;p&gt;There are many reasons why views might be expensive to render. For example, they might contain complex logic or require multiple database calls. In such cases, caching can be a useful technique to improve performance.&lt;/p&gt;
&lt;p&gt;We can use a plug to cache views in Phoenix. Here&amp;#39;s an example:&lt;/p&gt;
&lt;p&gt;Create a plug that checks if the view is cached and sends the cached content if it is. Otherwise, it continues with the pipeline and caches the response later.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.CacheViewPlug do
  import Plug.Conn

  def init(opts), do: opts

  def call(conn, _opts) do
    cache_key = &amp;quot;view_cache:#{conn.request_path}&amp;quot;

    case Cachex.get(:my_cache, cache_key) do
      {:ok, nil} -&amp;gt;
        # Cache miss, continue with the pipeline and cache the response later
        conn
      {:ok, cached_content} -&amp;gt;
        # Cache hit, send the cached content and halt the pipeline
        conn
        |&amp;gt; put_resp_content_type(&amp;quot;text/html&amp;quot;)
        |&amp;gt; send_resp(200, cached_content)
        |&amp;gt; halt()
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s break down what&amp;#39;s happening here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Module definition:&lt;/strong&gt; the &lt;code&gt;defmodule MyApp.CacheViewPlug do:&lt;/code&gt; line defines a new module named &lt;code&gt;MyApp.CacheViewPlug&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Importing Plug.Conn:&lt;/strong&gt; &lt;code&gt;import Plug.Conn:&lt;/code&gt; imports functions from the Plug.Conn module, which provides utilities for working with connection structs in the context of a Plug.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Initialization function:&lt;/strong&gt; &lt;code&gt;def init(opts), do: opts:&lt;/code&gt; is the initialization function required by the Plug behavior. It takes an opts argument (options) and simply returns it unchanged. In many Plugs, this function sets default options or validates the provided options. However, in this case, it&amp;#39;s a simple pass-through.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Call function:&lt;/strong&gt; &lt;code&gt;def call(conn, _opts) do:&lt;/code&gt; is the main Plug function that gets executed for every request. It takes two arguments: &lt;code&gt;conn&lt;/code&gt; (the connection struct) and &lt;code&gt;_opts&lt;/code&gt; (the options, which are ignored in this case).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generating the cache key:&lt;/strong&gt; &lt;code&gt;cache_key = &amp;quot;view_cache:#{conn.request_path}&amp;quot;:&lt;/code&gt; constructs a cache key based on the request path. The cache key is prefixed with &amp;quot;view_cache:&amp;quot; to namespace or differentiate it from other potential cache keys.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checking the cache:&lt;/strong&gt; The case &lt;code&gt;Cachex.get(:my_cache, cache_key) do&lt;/code&gt; statement checks the cache &lt;code&gt;(:my_cache)&lt;/code&gt; for content associated with the generated cache_key.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling cache results:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;{:ok, nil} -&amp;gt;&lt;/code&gt;: This pattern matches a cache miss. If the cache doesn&amp;#39;t have content for the given key, it returns &lt;code&gt;{:ok, nil}&lt;/code&gt;. In the event of a cache miss, the function simply returns the unchanged conn, allowing the request to continue through the Plug pipeline. The intention is that the response will be cached later, presumably by another part of the application.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{:ok, cached_content} -&amp;gt;&lt;/code&gt;: This pattern matches a cache hit. If the cache has content for the given key, it returns &lt;code&gt;{:ok, cached_content}&lt;/code&gt;. In this case, the function sends the cached content as the response, sets the response content type to &amp;quot;text/html&amp;quot;, and then halts the Plug pipeline to prevent further processing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, add the plug to your pipeline in &lt;code&gt;router.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;pipeline :browser do
  ...
  plug MyApp.CacheViewPlug
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, cache the view after rendering it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def some_action(conn, _params) do
  content = render(conn, &amp;quot;some_template.html&amp;quot;)
  cache_key = &amp;quot;view_cache:#{conn.request_path}&amp;quot;
  Cachex.put(:my_cache, cache_key, content)
  send_resp(conn, 200, content)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Caching API Responses&lt;/h4&gt;
&lt;p&gt;Another common Cachex use case for Phoenix is to cache API responses. This can be useful to reduce the load on external services and speed up data retrieval. Similar to caching views, we can use a plug to cache API responses in Phoenix.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a plug that checks if the response is cached and sends the cached content if it is. Otherwise, it continues with the pipeline and caches the response later.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.CacheAPIPlug do
  import Plug.Conn

  def init(opts), do: opts

  def call(conn, _opts) do
    # Create a cache key based on the request path and query parameters
    cache_key = &amp;quot;api_cache:#{conn.request_path}?#{conn.query_string}&amp;quot;

    case Cachex.get(:my_cache, cache_key) do
      {:ok, nil} -&amp;gt;
        # Cache miss, continue with the pipeline and cache the response later
        conn
      {:ok, {status, headers, body}} -&amp;gt;
        # Cache hit, send the cached response and halt the pipeline
        conn
        |&amp;gt; put_status(status)
        |&amp;gt; put_resp_header(&amp;quot;content-type&amp;quot;, List.keyfind(headers, &amp;quot;content-type&amp;quot;, 0, {&amp;quot;content-type&amp;quot;, &amp;quot;application/json&amp;quot;}))
        |&amp;gt; send_resp(status, body)
        |&amp;gt; halt()
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Add the plug to your pipeline in &lt;code&gt;router.ex&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;pipeline :api do
  ...
  plug MyApp.CacheAPIPlug
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Cache the response after sending it:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def some_api_action(conn, _params) do
  # Process the request and generate the response
  response = %{data: &amp;quot;Some API response data&amp;quot;}

  # Convert the response to JSON
  json_response = Jason.encode!(response)

  # Cache the response
  cache_key = &amp;quot;api_cache:#{conn.request_path}?#{conn.query_string}&amp;quot;
  cache_value = {200, [{&amp;quot;content-type&amp;quot;, &amp;quot;application/json&amp;quot;}], json_response}
  Cachex.put(:my_cache, cache_key, cache_value)

  # Send the response
  json(conn, response)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Checking for Stale Cache Data&lt;/h2&gt;
&lt;p&gt;One of the main challenges with caching is ensuring that the data in the cache is up-to-date. If data becomes stale, it can lead to incorrect results and a poor user experience. Therefore, it&amp;#39;s crucial to check for stale data and refresh the cache when necessary.&lt;/p&gt;
&lt;p&gt;Cachex provides built-in mechanisms to handle stale data, primarily through its Time-to-Live (TTL) and fallback features.&lt;/p&gt;
&lt;h3&gt;TTL&lt;/h3&gt;
&lt;p&gt;TTL allows you to specify how long an item should remain in the cache. Once the TTL expires, an item is automatically removed from the cache. This ensures that you don&amp;#39;t serve stale data older than a specified age.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Store data with a TTL of 3600 seconds (1 hour)
Cachex.put(:my_cache, &amp;quot;key&amp;quot;, &amp;quot;value&amp;quot;, ttl: 3600)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you attempt to retrieve this key after its TTL has expired, it will return as if the key does not exist in the cache.&lt;/p&gt;
&lt;h3&gt;Fallbacks&lt;/h3&gt;
&lt;p&gt;Cachex&amp;#39;s fallback mechanism is a powerful feature that allows you to execute a function when a cache miss occurs. This can be especially useful for handling stale data. If data is not in the cache (either because it was never cached or because it was evicted due to TTL expiration), the fallback function can fetch fresh data.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;fallback_fn = fn key -&amp;gt;
 # Fetch fresh data for the given key
 {:commit, fetch_fresh_data(key)}
end

# Attempt to get data from cache, use fallback if cache miss occurs
Cachex.fetch(:my_cache, &amp;quot;key&amp;quot;, fallback: fallback_fn)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;:commit&lt;/code&gt; tuple ensures that fetched data is stored back into the cache.&lt;/p&gt;
&lt;p&gt;By combining TTL and fallbacks, Cachex provides a robust mechanism to ensure that stale data is not served and that fresh data can be fetched and cached automatically when needed.&lt;/p&gt;
&lt;p&gt;One thing to note is the difference between &lt;code&gt;Cachex.get&lt;/code&gt; and &lt;code&gt;Cache.fetch&lt;/code&gt;. The &lt;code&gt;Cachex.get&lt;/code&gt; function returns the value associated with the given key, or &lt;code&gt;{:ok, nil}&lt;/code&gt; if the key is not found in the cache. The &lt;code&gt;Cachex.fetch&lt;/code&gt; function returns the value associated with the given key, or executes the fallback function if the key is not found in the cache. While both functions can be used to retrieve data from the cache, they have different behaviors when the key is not found. &lt;code&gt;Cachex.fetch&lt;/code&gt; offers more advanced mechanisms to handle cache misses.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s important to understand that the TTL and fallback features are not mutually exclusive, and can be used together to provide a more robust caching solution and a better user experience.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we&amp;#39;ve seen that caching is a powerful technique to significantly improve your Elixir application&amp;#39;s performance. However, we&amp;#39;ve also explored how caching is not without its drawbacks.&lt;/p&gt;
&lt;p&gt;Cachex, as representative of the vibrant Elixir ecosystem, showcases how community-driven tools can address complex problems with elegance and efficiency. But remember, Cachex is just the tip of the iceberg. The Elixir community is teeming with innovative libraries and frameworks, each solving unique challenges and pushing the boundaries of what&amp;#39;s possible.&lt;/p&gt;
&lt;p&gt;As you continue your journey with Elixir, I encourage you to explore the many tools and libraries available and discover how they can help you build better applications.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Creating Custom Exceptions in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/02/20/creating-custom-exceptions-in-elixir.html"/>
    <id>https://blog.appsignal.com/2024/02/20/creating-custom-exceptions-in-elixir.html</id>
    <published>2024-02-20T00:00:00+00:00</published>
    <updated>2024-02-20T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s run through the process of creating custom exceptions in Elixir.</summary>
    <content type="html">&lt;p&gt;Exceptions and exception handling are widely accepted concepts in most modern programming languages. Even though they&amp;#39;re not as prevalent in Elixir as in object-oriented languages, it&amp;#39;s still important to learn about them.&lt;/p&gt;
&lt;p&gt;In this article, we will closely examine exceptions in Elixir, learning how to define and use them.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Elixir and Exceptions&lt;/h2&gt;
&lt;p&gt;There is no single golden rule that covers when to use exceptions, especially custom ones. Throughout this article, I will keep to a &lt;a href=&quot;https://stackoverflow.com/a/77361&quot;&gt;definition of exceptions from StackOverflow&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An exception is thrown when a fundamental assumption of the current code block is found to be false.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, we can expect an exception when something truly &lt;em&gt;exceptional&lt;/em&gt; and hard to predict happens. Network failures, databases going down, or running out of memory — these are all good examples of when an exception should be thrown. However, if the form input you send to your server does not pass validation, there are better expressions to use, such as error tuples.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Check out our &lt;a href=&quot;https://blog.appsignal.com/2023/09/26/an-introduction-to-exceptions-in-elixir.html&quot;&gt;An Introduction to Exceptions in Elixir&lt;/a&gt; post for an overview of exceptions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You might wonder how Erlang&amp;#39;s famous &amp;quot;let it crash&amp;quot; philosophy works with exceptions. I would say it works pretty well. Exceptions are, in fact, crashes, as long as you don&amp;#39;t catch them.&lt;/p&gt;
&lt;h3&gt;The Anatomy of Elixir&amp;#39;s Exceptions&lt;/h3&gt;
&lt;p&gt;The most common exception you may have seen is probably &lt;code&gt;NoMatchError&lt;/code&gt;. And if you&amp;#39;ve used Ecto with PostgreSQL, you also must have seen &lt;code&gt;Postgrex.Error&lt;/code&gt; at least a few times. Among other popular exceptions, we have &lt;code&gt;CaseClauseError&lt;/code&gt;, &lt;code&gt;UndefinedFunctionError&lt;/code&gt;, or &lt;code&gt;ArithmeticError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s now take a look at what exceptions are under the hood. The easiest way to do that is to cause an exception, rescue it, and then inspect it. We will use the following code to dissect &lt;code&gt;NoMatchError&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Test do
  def test(x) do
    :ok = x
  end
end

try do
  Test.test(:not_ok)
rescue
  ex -&amp;gt; IO.inspect(ex)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output will be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;%MatchError{term: :not_ok}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see, this is just a struct with some additional data. Using similar code, we can check &lt;code&gt;CaseClauseError&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;%CaseClauseError{term: :not_ok}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can do more using functions provided by the &lt;code&gt;Exception&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;gt; Exception.exception?(ex) # note that this is deprecated in favour of Kernel.is_exception
true
&amp;gt; Exception.message(ex)
&amp;quot;no case clause matching: :not_ok&amp;quot;
&amp;gt; Exception.format(:error, ex)
&amp;quot;** (CaseClauseError) no case clause matching: :not_ok&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And can peek even deeper by using functions from the &lt;code&gt;Map&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;gt; Map.keys(ex)
[:__exception__, :__struct__, :term]
&amp;gt; ex.__struct__
CaseClauseError
&amp;gt; ex.__exception__
true
&amp;gt; ex.term
:not_ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Armed with that knowledge, we create a &amp;quot;fake&amp;quot; exception using just a map:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;gt; Exception.format(:error, %{__struct__: CaseClauseError, __exception__: true, term: :not_ok})
&amp;quot;** (CaseClauseError) no case clause matching: :not_ok&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this is not how we will define our custom exception. And before we dive into custom exceptions, let&amp;#39;s try to answer one important question: when should we use them?&lt;/p&gt;
&lt;h2&gt;When Should You Use Custom Exceptions?&lt;/h2&gt;
&lt;p&gt;The most common use case for custom exceptions is when you are creating your own library. Take Postgrex, for example: you have &lt;code&gt;Postgrex.Error&lt;/code&gt;. In Tesla (an HTTP client), you have &lt;code&gt;Tesla.Error&lt;/code&gt;. They are useful because they immediately indicate where an error happens and how to determine its cause.&lt;/p&gt;
&lt;p&gt;Most of us, however, do not write libraries often. It&amp;#39;s more likely that you work on a specific application that powers your company&amp;#39;s business (or its customers). Even in your application&amp;#39;s code, it can be useful to define some custom exceptions.&lt;/p&gt;
&lt;p&gt;For example, your application might send webhook notifications to a URL defined in an environment variable. Consider this very simplified code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WebhookSender do
  def send(payload) do
      url = System.get_env(&amp;quot;WEBHOOK_ENDPOINT&amp;quot;)
      HttpClient.post(url, payload)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can reasonably expect that a &lt;code&gt;WEBHOOK_ENDPOINT&lt;/code&gt; environment variable is set on a machine where your application is deployed. If it&amp;#39;s not, that&amp;#39;s a misconfiguration. To paraphrase the &lt;a href=&quot;https://stackoverflow.com/questions/77127/when-to-throw-an-exception/77361#77361&quot;&gt;earlier definition of exceptions from StackOverflow&lt;/a&gt;, it&amp;#39;s a &amp;quot;fundamental assumption of the current code being false&amp;quot;.&lt;/p&gt;
&lt;p&gt;Of course, running that code when &lt;code&gt;System.get_env&lt;/code&gt; call evaluates to &lt;code&gt;nil&lt;/code&gt; &lt;strong&gt;will&lt;/strong&gt; result in an exception from &lt;code&gt;HttpClient&lt;/code&gt;. However, instead, you can be more defensive and perform a direct check in the &lt;code&gt;WebhookSender&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;Imagine you swap &lt;code&gt;HttpClient&lt;/code&gt; for &lt;code&gt;BetterHttpClient&lt;/code&gt; in the future, and all exceptions change. Now, throughout your application, you must fix all the places where you use a reported exception (for example, when providing an informative error message to the client). And this is because you changed a dependency, an implementation detail.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;How to Define a Custom Exception in Elixir&lt;/h2&gt;
&lt;p&gt;As we have seen, exceptions in Elixir are just &amp;quot;special&amp;quot; structs. They are special because they have an &lt;code&gt;__exception__&lt;/code&gt; field, which holds a value of &lt;code&gt;true&lt;/code&gt;. While we could just use a &lt;code&gt;Map&lt;/code&gt; of regular &lt;code&gt;defstruct&lt;/code&gt;, this exception would not work nicely with all the tooling around exceptions.&lt;/p&gt;
&lt;p&gt;To define a proper exception, we should use the &lt;code&gt;defexception&lt;/code&gt; macro. Let&amp;#39;s do this for the webhook example we looked at earlier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WebhookSender.ConfigurationError do
  defexception [:message]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is as simple as that. You can then improve the code of the &lt;code&gt;WebhookSender&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WebhookSender do
  def send(payload) do
      case System.get_env(&amp;quot;WEBHOOK_ENDPOINT&amp;quot;) do
        nil -&amp;gt; raise ConfigurationError, message: &amp;quot;WEBHOOK_ENDPOINT env var not defined&amp;quot;
        url -&amp;gt; HttpClient.post(url, payload)
      end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you run this code (of course, assuming the variable is not set), it will show an error just like with a regular exception:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;** (WebhookSender.ConfigurationError) WEBHOOK_ENDPOINT env var not defined
    exceptions_test.exs:24: (file)
    (elixir 1.14.0) lib/code.ex:1245: Code.require_file/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This exception clearly shows where the error originated from: a &lt;code&gt;WebhookSender&lt;/code&gt; module. Imagine that, instead, you see something like &lt;code&gt;HttpClient.CannotPerformRequest&lt;/code&gt; here. Chances are you are using &lt;code&gt;HttpClient&lt;/code&gt; in multiple places in the application. First, you must traverse the stack trace and find out which &lt;code&gt;HttpClient&lt;/code&gt; invocation is the culprit. Then, you still have to figure out the actual reason for the error.&lt;/p&gt;
&lt;p&gt;Note that &lt;code&gt;:message&lt;/code&gt; is just an example of a field you can define on the exception. Although it&amp;#39;s a nice default, it is not strictly needed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SpaceshipConstruction.IncompatibleModules do
  defexception [:module_a, :module_b]
end

raise SpaceshipConstruction.IncompatibleModules,
  module_a: LithiumLoadingBay,
  module_b: OxygenTreatmentPlant
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When this code runs, however, it will crash on attempting to format the exception message:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;** (SpaceshipConstruction.IncompatibleModules) got UndefinedFunctionError with message &amp;quot;function SpaceshipConstruction.IncompatibleModules.message/1 is undefined or private&amp;quot; while retrieving Exception.message/1 for %SpaceshipConstruction.IncompatibleModules{module_a: LithiumLoadingBay, module_b: OxygenTreatmentPlant}. Stacktrace:
    SpaceshipConstruction.IncompatibleModules.message(%SpaceshipConstruction.IncompatibleModules{module_a: LithiumLoadingBay, module_b: OxygenTreatmentPlant})
    (elixir 1.14.0) lib/exception.ex:66: Exception.message/1
    (elixir 1.14.0) lib/exception.ex:117: Exception.format_banner/3
    (elixir 1.14.0) lib/kernel/cli.ex:102: Kernel.CLI.format_error/3
    (elixir 1.14.0) lib/kernel/cli.ex:183: Kernel.CLI.print_error/3
    (elixir 1.14.0) lib/kernel/cli.ex:145: anonymous fn/3 in Kernel.CLI.exec_fun/2

    space_exceptions.exs:5: (file)
    (elixir 1.14.0) lib/code.ex:1245: Code.require_file/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are two ways to fix this without having to manually pass an error message every time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a &lt;code&gt;message/1&lt;/code&gt; function to an exception module.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SpaceshipConstruction.IncompatibleModules do
  defexception [:module_a, :module_b]
  def message(_), do: &amp;quot;Given modules are not compatible&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, an argument to the function is an exception itself, so you can construct a more precise error message from it. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def message(exception) do
  &amp;quot;Module #{exception.module_a} and #{exception.module_b} are not compatible&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Provide a default message.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SpaceshipConstruction.IncompatibleModules do
  defexception [:module_a, :module_b, message: &amp;quot;Given modules are not compatible&amp;quot;]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Repackaging Exceptions&lt;/h2&gt;
&lt;p&gt;One interesting use case for custom exceptions is when you want to &amp;quot;repackage&amp;quot; an existing exception to fit a specific condition. This can make the exception stand out more in your error tracker.&lt;/p&gt;
&lt;p&gt;For example, we did that with database deadlocks at the company I work for. Deadlocks are one of the hardest database-related errors to track, but they are just reported as &lt;code&gt;Postgrex.Error&lt;/code&gt;. We wanted clearer visibility over when these errors happen (compared to other &lt;code&gt;Postgrex.Error&lt;/code&gt;s) and on which GraphQL mutations.&lt;/p&gt;
&lt;p&gt;So, I added an &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Middleware.html&quot;&gt;Absinthe middleware&lt;/a&gt; checking for the exception. It looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Middlewares.ExceptionHandler do
  alias Absinthe.Resolution
  @behaviour Absinthe.Middleware

  def call(resolution, resolver) do
    Resolution.call(resolution, resolver)
  rescue
    exception -&amp;gt;
      error = Exception.format(:error, exception, __STACKTRACE__)

      if String.match?(error, ~r/ERROR 40P01/) do
        report_deadlock(exception, __STACKTRACE__)
      else
          @error_reporter.report_exception(exception, stacktrace: __STACKTRACE__)
      end

    resolution
  end

  defp report_deadlock(ex, stacktrace) do
      original_message = Exception.message(ex)
      mutation = get_mutation_name_from_process_metadata()
      try do
      reraise DeadlockDetected,
        [message: &amp;quot;Deadlock in mutation #{mutation}\n\n#{original_message}&amp;quot;],
        stacktrace
    rescue
      exception -&amp;gt;
        @error_reporter.report_exception(exception,
          stacktrace: __STACKTRACE__
        )
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This might seem like a lot of code. Let&amp;#39;s break it down a little. When an exception is raised, we check if its message contains &lt;code&gt;ERROR 40P01&lt;/code&gt; (code for a deadlock).&lt;/p&gt;
&lt;p&gt;Then, we raise a custom &lt;code&gt;DeadlockDetected&lt;/code&gt; exception and immediately rescue it to send it to an &lt;a href=&quot;https://www.appsignal.com/tour/errors&quot;&gt;error reporter, such as AppSignal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, instead of generic &lt;code&gt;Postgrex.Error&lt;/code&gt;s, often mixed with other database exceptions, we have a separate class of exceptions just dedicated to deadlocks. And custom exception messages allow us to quickly identify the mutation with deadlock-unsafe code.&lt;/p&gt;
&lt;h2&gt;Repackaging Exits as Exceptions&lt;/h2&gt;
&lt;p&gt;Another case for custom exceptions is when you want to transform an exit into an exception. This might be because your error reporting software does not support exits, or you may just want a more specific message than the default.&lt;/p&gt;
&lt;p&gt;The most common case for exits is timeouts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ImportantTask do
  def run do
    task = Task.async(fn -&amp;gt; :timer.sleep(200) end)
    Task.await(task, 100)
  end
end

ImportantTask.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, we spawn an async task that takes 200 milliseconds to complete, but we allow it to run for 100 ms. Here&amp;#39;s the result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;** (exit) exited in: Task.await(%Task{mfa: {:erlang, :apply, 2}, owner: #PID&amp;lt;0.96.0&amp;gt;, pid: #PID&amp;lt;0.103.0&amp;gt;, ref: #Reference&amp;lt;0.131053822.3597205508.67962&amp;gt;}, 100)
    ** (EXIT) time out
    (elixir 1.14.0) lib/task.ex:830: Task.await/2
    (elixir 1.14.0) lib/code.ex:1245: Code.require_file/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s pretty generic, isn&amp;#39;t it? Let&amp;#39;s make it a bit nicer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ImportantTask do
  defmodule Timeout do
    defexception [:message]
  end

  def run do
    task = Task.async(fn -&amp;gt; :timer.sleep(200) end)
    Task.await(task, 100)
  catch
  :exit, {:timeout, _} = reason -&amp;gt;
      error = Exception.format_exit(reason)
      raise Timeout, message: error
  end
end

ImportantTask.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we define a custom &lt;code&gt;Timeout&lt;/code&gt; exception, then catch an exit and raise an exception instead. The result is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;** (ImportantTask.Timeout) exited in: Task.await(%Task{mfa: {:erlang, :apply, 2}, owner: #PID&amp;lt;0.96.0&amp;gt;, pid: #PID&amp;lt;0.106.0&amp;gt;, ref: #Reference&amp;lt;0.342776.2255814665.42176&amp;gt;}, 100)
    ** (EXIT) time out
    exits_to_exceptions.exs:12: ImportantTask.run/0
    (elixir 1.14.0) lib/code.ex:1245: Code.require_file/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While you may consider that this error message is still a bit cryptic, it adds two main quality-of-life improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;ImportantTask.Timeout&lt;/code&gt; exception, which makes it easy to assign the error to a particular piece of functionality in your code.&lt;/li&gt;
&lt;li&gt;A line from our code in the stack trace (&lt;code&gt;exits_to_exceptions.exs:12: ImportantTask.run/0&lt;/code&gt;). Note that the default exit message does not include this, so it&amp;#39;s much harder to find the offending place in the code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we learned how to define custom exceptions in Elixir. They are very useful when building a library, but they also have their place in your application code.&lt;/p&gt;
&lt;p&gt;By repackaging generic exceptions or trapping and re-raising exits, you can make your code much easier to debug if something goes wrong. Your future self (and your colleagues) will be grateful!&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Build a Memory-efficient Elixir App with Streams</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/02/06/how-to-build-a-memory-efficient-elixir-app-with-streams.html"/>
    <id>https://blog.appsignal.com/2024/02/06/how-to-build-a-memory-efficient-elixir-app-with-streams.html</id>
    <published>2024-02-06T00:00:00+00:00</published>
    <updated>2024-02-06T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s create a memory-efficient Elixir application using the lazy processing approach with streams.</summary>
    <content type="html">&lt;p&gt;We have all encountered collections of data at some point when working on Elixir applications. These collections are very handy for storing, retrieving, and manipulating data using different data structures, making them very efficient in managing clean code.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll go through the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are collections in Elixir?&lt;/li&gt;
&lt;li&gt;The problems likely to be faced when working with collections&lt;/li&gt;
&lt;li&gt;The greedy approach when working with large datasets&lt;/li&gt;
&lt;li&gt;The enumerable in Elixir, used to work around collections&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, we&amp;#39;ll explore how to build a memory-efficient Elixir application using the lazy processing approach with streams.&lt;/p&gt;
&lt;h2&gt;What are Collections in Elixir?&lt;/h2&gt;
&lt;p&gt;You can view a collection as a container that groups multiple things/objects/elements into a single unit. This collection allows you to store, retrieve, and manipulate data.&lt;/p&gt;
&lt;p&gt;A couple of examples of collections encountered in the real world include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A mail folder that contains received and sent letters.&lt;/li&gt;
&lt;li&gt;A phone directory mapping phone numbers to corresponding names.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Elixir, &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Maps&lt;/code&gt;, &lt;code&gt;Ranges&lt;/code&gt;, &lt;code&gt;files&lt;/code&gt;, and &lt;code&gt;tuples&lt;/code&gt; are the most common types of collections. Some of these collections can be iterated through. Each element is passed through once, in order, so we can term them &lt;code&gt;enumerables&lt;/code&gt;. Things that can be iterated in Elixir implement the &lt;a href=&quot;https://hexdocs.pm/elixir/Enumerable.html#functions&quot;&gt;Enumerable protocol&lt;/a&gt;. &lt;code&gt;List&lt;/code&gt;, &lt;code&gt;Maps&lt;/code&gt;, and &lt;code&gt;Ranges&lt;/code&gt; are the most common datatypes used as enumerables.&lt;/p&gt;
&lt;p&gt;Elixir has two modules with iteration functions that use the Enumerable protocol: &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html#content&quot;&gt;Enum&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Stream.html&quot;&gt;Stream&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The Challenges of Collections&lt;/h2&gt;
&lt;p&gt;Working with collections can be very efficient, especially when your collections aren&amp;#39;t that large. However, manipulating these collections can be very difficult when dealing with large datasets.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s say we want to retrieve organization data from a CSV file and display it in our application. Ideally, we have to load all the organizations from the CSV file into an application&amp;#39;s memory and transform the retrieved data into the data we want.&lt;/p&gt;
&lt;p&gt;Our application can be safe if the memory contains a predictable number of organizations that can be easily transformed or manipulated. However, if we have extensive data on organizations retrieved from the CSV, managing this data can result in slow application performance, because more memory is needed to consume it.&lt;/p&gt;
&lt;p&gt;So, how can we elegantly manage our large CSV file? (keeping in mind some of the problems we might face while processing it).&lt;/p&gt;
&lt;p&gt;We can process our CSV file using one of two approaches:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The greedy approach that consumes more memory.&lt;/li&gt;
&lt;li&gt;The memory-efficient lazy processing approach.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Earlier, we mentioned that Elixir has two modules, &lt;code&gt;Enum&lt;/code&gt; and &lt;code&gt;Stream&lt;/code&gt;, with iteration functions. We&amp;#39;ll use these modules to process our CSV file.&lt;/p&gt;
&lt;h3&gt;The Greedy Approach For Our Elixir Application&lt;/h3&gt;
&lt;p&gt;In the greedy approach, we are going to use the Enum module because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When given a collection, it will consume all the content of that collection. That means the whole collection should be loaded into memory before being processed.&lt;/li&gt;
&lt;li&gt;The returned result is another collection that will be loaded into memory, which might be inefficient if data is not needed at that time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#39;s process our CSV file greedily.&lt;/p&gt;
&lt;p&gt;We shall use an organization&amp;#39;s CSV file with 2,000,000 records &lt;a href=&quot;https://www.datablist.com/learn/csv/download-sample-csv-files&quot;&gt;downloaded from here&lt;/a&gt; for demonstration purposes. The size of the CSV file (after unzipping) is around 283.4MB.&lt;/p&gt;
&lt;p&gt;Our focus will be to get the records of all organizations and transform them into data we can easily display in the browser. The result should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[
%{
index: &amp;quot;1&amp;quot;,
organization_id: &amp;quot;1234&amp;quot;,
name: &amp;quot;PLC&amp;quot;,
website: &amp;quot;https://park.com/&amp;quot;,
country: &amp;quot;Kenya&amp;quot;,
description: &amp;quot;Focused for the best&amp;quot;,
founded: &amp;quot;2016&amp;quot;,
industry: &amp;quot;sports&amp;quot;,
num_of_employees: 300

},..
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we begin, let&amp;#39;s open the interactive shell to manipulate the CSV file. After that, start the &lt;code&gt;Erlang Observer&lt;/code&gt; application by running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; :observer.start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We shall use the &lt;code&gt;Observer&lt;/code&gt; application to inspect memory allocators when processing the CSV file.&lt;/p&gt;
&lt;h3&gt;Step 1: Loading the CSV File Into Memory&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;File.read!(&amp;quot;organization.csv&amp;quot;)&lt;/code&gt; to load the whole CSV file into memory. The observer shows an extra 283.84 MB allocated to memory.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-02/greedy-approach-step1.png&quot; alt=&quot;file opening&quot;/&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; org_csv = File.read!(&amp;quot;organization.csv&amp;quot;)


    &amp;quot;Index,Organization Id,Name,Website,Country,Description,Founded,Industry,Number of employees\r\n1,391dAA77fea9EC1,Daniel-Mcmahon,https://stuart-rios.biz/,Cambodia,Focused eco-centric help-desk,2013,Sports,1878\r\n2,9FcCA4A23e6BcfA, Mcdowell,http://jacobs.biz/,Guyana,Front-line real-time portal,2018,Legal Services,9743\r\n3,DB23330238B7B3D,\&amp;quot;Roberts, Carson and Trujillo\&amp;quot;,http://www.park.com/,Jordan,Innovative hybrid data-warehouse,1992,Hospitality,7537\r\n4,bbf18835CFbEee7,\&amp;quot;Poole, Jefferson and Merritt\&amp;quot;,http://hayden.com/,Cocos (Keeling) Islands,Extended regional Graphic Interface,1991,Food Production,9974\r\n5,74ECD725ceaDfd9,\&amp;quot;Ritter, Patel and Cisneros\&amp;quot;,https://www.mason-blackwell.info/,Ecuador,Re-contextualized actuating website,2019,Computer Networking,5050\r\n6,ea42e2FECDAdF0c,Stafford Ltd,http://www.fuller.biz/,Qatar,Multi-channeled optimizing customer loyalty,1979,Aviation / Aerospace,7506\r\n7,b8EE5AE2Df8BA46,Roach Ltd,https://www.oconnell.com/,Guatemala,Switchable explicit complexity,2020,Hospitality,109\r\n8,21829Cf5a968024,Gill PLC,https://www.berry.com/,Lesotho,Future-proofed systemic pricing structure,1983,Printing,1822\r\n9,f9C605c034f47cD,Summers-Jordan,https://le.net/,Luxembourg,Cross-platform bottom-line system engine,1976,Primary / Secondary Education,1603\r\n10,0fBa55ecDA6cb4B,\&amp;quot;Richard, Lane and Weaver\&amp;quot;,https://bauer-hardy.com/,United States Minor Outlying Islands,Optimized system-worthy complexity,2006,Building Materials,3505\r\n11,d085befF19Be6fB,\&amp;quot;Harrington, Sutton and Wilkins\&amp;quot;,http://henson.com/,Guinea-Bissau,Diverse scalable instruction set,1985,Airlines / Aviation,1926\r\n12,13B77fAF602E949,Evans LLC,http://harrington-powers.com/,Cook Islands,Re-contextualized stable flexibility,2017,Design,3338\r\n13,90234C8d0D7eB75,\&amp;quot;Patterson, Deleon and Donovan\&amp;quot;,https://thornton.net/,Holy See (Vatican City State),Versatile encompassing migration,1970,Automotive,9312\r\n14,155A7db5D8Cce47,\&amp;quot;Carlson, Snyder and Holland\&amp;quot;,http://foley.com/,Korea,Devolved optimal secured line,1979,International Trade / Development,2649\r\n15,77B7F7fb1Ac2A44,Duffy-Stark,https://www.morales.com/,Monaco,Re-contextualized 24/7 Graphical User Interface,1990,Aviation / Aerospace,1714\r\n16,1f6bABBA98cd33E,\&amp;quot;Frederick, Fry and Poole\&amp;quot;,http://www.madden.org/,Vanuatu,Synchronized empowering structure,2008,Fishery,1862\r\n17,05dbf87Ee09b6BC,\&amp;quot;Walton, Proctor and Peters\&amp;quot;,http://www.casey-bell.com/,Grenada,Diverse local collaboration,1979,Alternative Medicine,4678\r\n18,20ef50A2fdB3993,Oneal and Sons,http://munoz.org/,Fiji,Operative uniform definition,1987,Religious Institutions,8332\r\n19,a9C703D1A2B074C,Maynard-Bush,http://leblanc.com/,Senegal,Customizable zero tolerance functionalities,2011,Apparel / Fashion,1668\r\n20,1ea33Ac2face255,\&amp;quot;Rosario, Martin and White\&amp;quot;,https://www.mueller-rhodes.net/,Isle of Man,Synchronized 6thgeneration flexibility,1994,Music,5134\r\n21,CDCAe4a6DA0eC6d,Brady Ltd,http://montgomery.biz/,Guyana,Self-enabling modular archive,1989,Professional Training,5153\r\n22,f41b9Ce917bDD28,Odom Group,http://www.riley-dalton.net/,Saint Kitts and Nevis,Grass-roots bandwidth-monitored projection,2003,Computer Hardware,4793\r\n23,B1181c8C3d43216,Stanton-Arroyo,http://baird.org/,Montserrat,Integrated empowering core,1976,Mental Health Care,6919\r\n24,b3E9C4E4cbC4a8e,Stafford-Hickman,https://love.net/,United States Virgin Islands,Virtual background application,1996,Hospital / Health Care,3855\r\n25,f92AacaEEcB6eC6,Ryan and Sons,http://koch-raymond.org/,Chad,Public-key maximized definition,2017,Airlines / Aviation,1564\r\n26,8eb91E6eeDBC2A5,Wolf Group,https://aguilar-solomon.net/,Cayman Islands,Public-key value-added alliance,1984,Package / Freight Delivery,4509\r\n27,fDaeD26dB6fd79a,\&amp;quot;Horne, Bailey and Oconnor\&amp;quot;,https://cruz.com/,Western Sahara,Customer-focused needs-based service-desk,1973,Wholesale,2670\r\n28,19Bbb8dB90dFaFF,Cobb Inc,http://miles.com/,Netherlands,Assimilated local ability,2008,Political Organization,2494\r\n29,00AF7EacF3fEb91,Parrish-Peterson,https://strong.org/,France,Multi-lateral encompassing structure,2004,Political Organization,9059\r\n30,8Ec27fFD6b945A9,\&amp;quot;Barr&amp;quot; &amp;lt;&amp;gt; ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Create a List for Each Row In the CSV&lt;/h3&gt;
&lt;p&gt;The data in Step 1 is loaded text, which means we are still far from our end goal. In this step, let&amp;#39;s take the loaded text data and split it into lines. This will result in a list of string elements, with each element representing a row of the CSV.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; [_header | rows] = org_csv |&amp;gt; String.split(&amp;quot;\n&amp;quot;)

     [&amp;quot;Index,Organization Id,Name,Website,Country,Description,Founded,Industry,Number of employees\r&amp;quot;,
 &amp;quot;1,391dAA77fea9EC1,Daniel-Mcmahon,https://stuart-rios.biz/,Cambodia,Focused eco-centric help-desk,2013,Sports,1878\r&amp;quot;,
 &amp;quot;2,9FcCA4A23e6BcfA,Mcdowell, http://jacobs.biz/,Guyana,Front-line real-time portal,2018,Legal Services,9743\r&amp;quot;,
...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The observer shows an increase in allocated memory:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-02/greedy-approach-step2.png&quot; alt=&quot;step 2 greedy approach&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Step 3: Create a Column from Each Row&lt;/h3&gt;
&lt;p&gt;In the second step, we pattern-matched our result to &lt;code&gt;[_header | rows]&lt;/code&gt;. We are not interested in the header of the CSV file, but in the body.&lt;/p&gt;
&lt;p&gt;In this step, we will split each row into a list, with the elements in each list representing a column of the CSV file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; org_records = rows |&amp;gt; Enum.map(&amp;amp;String.split(&amp;amp;1, &amp;quot;,&amp;quot;))

  [
    [&amp;quot;1&amp;quot;, &amp;quot;391dAA77fea9EC1&amp;quot;, &amp;quot;Daniel-Mcmahon&amp;quot;, &amp;quot;https://stuart-rios.biz/&amp;quot;,
     &amp;quot;Cambodia&amp;quot;, &amp;quot;Focused eco-centric help-desk&amp;quot;, &amp;quot;2013&amp;quot;, &amp;quot;Sports&amp;quot;, &amp;quot;1878\r&amp;quot;],
    [&amp;quot;2&amp;quot;, &amp;quot;9FcCA4A23e6BcfA&amp;quot;, &amp;quot;Mcdowell&amp;quot;,
     &amp;quot;http://jacobs.biz/&amp;quot;, &amp;quot;Guyana&amp;quot;, &amp;quot;Front-line real-time portal&amp;quot;, &amp;quot;2018&amp;quot;,
     &amp;quot;Legal Services&amp;quot;, &amp;quot;9743\r&amp;quot;],
...]
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;This step alone takes almost 60 seconds to process. The observer also shows a spike increase in memory allocation:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-02/greedy-approach-step3.png&quot; alt=&quot;step 3 greedy approach&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Step 4: Create a Keyword List of Each Row&lt;/h3&gt;
&lt;p&gt;Here, each column in each row will be zipped to its corresponding header name.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; org_records = org_records |&amp;gt; Enum.map(fn record -&amp;gt;  Enum.zip([:org_id, :name, :website, :country, :description, :founded, :industry, :number_of_employees], record) end)
    [
      [
       index: &amp;quot;1&amp;quot;,
       org_id: &amp;quot;391dAA77fea9EC1&amp;quot;,
       name: &amp;quot;Daniel-Mcmahon&amp;quot;,
       website: &amp;quot;https://stuart-rios.biz/&amp;quot;,
       country: &amp;quot;Cambodia&amp;quot;,
       description: &amp;quot;Focused eco-centric help-desk&amp;quot;,
       founded: &amp;quot;2013&amp;quot;,
       industry: &amp;quot;Sports&amp;quot;,
       number_of_employees: &amp;quot;1878&amp;quot;
      ],
      [
        index: &amp;quot;2&amp;quot;,
        org_id: &amp;quot;9FcCA4A23e6BcfA&amp;quot;,
        name: &amp;quot;Mcdowell&amp;quot;,
        website: &amp;quot;http://jacobs.biz/&amp;quot;,
        country: &amp;quot;Guyana&amp;quot;,
        description: &amp;quot;Front-line real-time portal&amp;quot;,
        founded: &amp;quot;2018&amp;quot;,
        industry: &amp;quot;Legal Services&amp;quot;,
        number_of_employees: &amp;quot;9743&amp;quot;
      ],
...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, we use &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html#map/2&quot;&gt;Enum.map/2&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html#zip/2&quot;&gt;Enum.zip/2&lt;/a&gt; to process the organization record results from step 3 (a list of lists, where each list element represents a row of records). Remember that each call to the Enum module takes a collection and returns a collection. Both &lt;code&gt;Enum.map/2&lt;/code&gt; and &lt;code&gt;Enum.zip/2&lt;/code&gt; will greedily process our data, which explains the spike increase in memory allocation as seen from the observer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-02/greedy-approach-final-step.png&quot; alt=&quot;step 4 greedy approach&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Enum.map/2&lt;/code&gt; takes in a list of lists, where each list element is a row of organization records. It iterates through each corresponding row and invokes &lt;code&gt;Enum.zip/2&lt;/code&gt; on each row to transform it into a keyword list.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Enum.zip/2&lt;/code&gt; function takes in two enumerables. The first enumerable is a list of header names, and the second is a list of each row. The &lt;code&gt;zip&lt;/code&gt; function zips the corresponding elements from the list of headers and the list of each row into a list of tuples. The tuple element in the list has an atom as the first element (which is the header name and value of the corresponding header name).&lt;/p&gt;
&lt;p&gt;Elixir represents this kind of output as a keyword list. In your interactive shell, you will notice each row is transformed into a keyword list, but not a list of tuples.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Enum.map/2&lt;/code&gt; returns a new list of keyword lists.&lt;/p&gt;
&lt;h3&gt;Step 5: Convert to Map&lt;/h3&gt;
&lt;p&gt;Remember, our end goal was to work with data that&amp;#39;s easy to manipulate when we want to display a list of organizations. In this final step, we will convert the keyword list above into maps.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; org_records |&amp;gt; Enum.map(fn data -&amp;gt; Map.new(data) end)

    [
      %{
        index: &amp;quot;1&amp;quot;,
        org_id: &amp;quot;391dAA77fea9EC1&amp;quot;,
        name: &amp;quot;Daniel-Mcmahon&amp;quot;,
        website: &amp;quot;https://stuart-rios.biz/&amp;quot;,
        country: &amp;quot;Cambodia&amp;quot;,
        description: &amp;quot;Focused eco-centric help-desk&amp;quot;,
        founded: &amp;quot;2013&amp;quot;,
        industry: &amp;quot;Sports&amp;quot;,
        number_of_employees: &amp;quot;1878&amp;quot;
      },
      %{
        index: &amp;quot;2&amp;quot;,
        org_id: &amp;quot;9FcCA4A23e6BcfA&amp;quot;,
        name: &amp;quot;Mcdowell&amp;quot;,
        website: &amp;quot;http://jacobs.biz/&amp;quot;,
        country: &amp;quot;Guyana&amp;quot;,
        description: &amp;quot;Front-line real-time portal&amp;quot;,
        founded: &amp;quot;2018&amp;quot;,
        industry: &amp;quot;Legal Services&amp;quot;,
        number_of_employees: &amp;quot;9743&amp;quot;
      },
...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compiling everything together:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; [_| rows ] =
  &amp;quot;organization.csv&amp;quot;
 |&amp;gt;  File.read!()
 |&amp;gt;  String.split(&amp;quot;\n&amp;quot;)
 |&amp;gt; Enum.map(&amp;amp;String.split(&amp;amp;1, &amp;quot;,&amp;quot;))


iex &amp;gt;
   rows
|&amp;gt; Enum.map(fn record -&amp;gt;  Enum.zip([:org_id, :name, :website, :country, :description, :founded, :industry, :number_of_employees], record) end)
|&amp;gt; Enum.map(fn record -&amp;gt; Map.new(record) end)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Observation with &lt;code&gt;Enum&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;In each &lt;code&gt;Enum&lt;/code&gt; step, we generated an output before the final result. The intermediate result in each step is stored in memory as a full collection. That&amp;#39;s because, with Enum implementation, the whole collection must be available for the next step in the pipeline to start processing.&lt;/li&gt;
&lt;li&gt;With Enum, each step has to wait for its intermediate result to start processing, so it takes more time to process data in each step.&lt;/li&gt;
&lt;li&gt;There is a spike increase in memory allocation in each step, meaning an intermediate output must be kept in memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The greedy approach, or working with Enum, works well with a predictable number of elements. We couldn&amp;#39;t have easily noticed these problems in a small CSV file.&lt;/p&gt;
&lt;p&gt;However, this approach is very inefficient when we have to keep an intermediate result in memory in each step. This is a massive waste of memory that can lead to slow application performance.&lt;/p&gt;
&lt;h2&gt;Solution: Build a Memory-efficient Elixir App with Streams&lt;/h2&gt;
&lt;p&gt;First, what are our goals?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Memory allocation that&amp;#39;s only for the final result.&lt;/li&gt;
&lt;li&gt;To process records only when we need them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Using streams, we can do these things. Streams are known to be lazy enumerables.&lt;/p&gt;
&lt;p&gt;This is because streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lazily load data into memory: That is, one element at a time instead of loading everything at once.&lt;/li&gt;
&lt;li&gt;Only load data when needed.&lt;/li&gt;
&lt;li&gt;Instead of applying a transformation to the given enumerable, return a value with the intended specifications.&lt;/li&gt;
&lt;li&gt;Process one piece of data at a time as it arrives instead of waiting for the whole collection to be available.&lt;/li&gt;
&lt;li&gt;Are a composable enumerator that reads and pipes one single line at a time without needing to wait for all the passed data to be processed at every single step.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Lazy Processing Approach with Streams in Elixir&lt;/h3&gt;
&lt;p&gt;We can leverage lazy processing to process our organization&amp;#39;s CSV file.&lt;/p&gt;
&lt;p&gt;The good thing is that more Elixir modules now support streams. Instead of opening the CSV file and loading the data on step 1, let&amp;#39;s use &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/File.html#stream!/3&quot;&gt;&lt;code&gt;File.stream!/3&lt;/code&gt;&lt;/a&gt; to create a stream without necessarily opening the file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; File.stream!(&amp;quot;/org.csv&amp;quot;)
    %File.Stream{
      line_or_bytes: :line,
      modes: [:raw, :read_ahead, :binary],
      path: &amp;quot;/org.csv&amp;quot;,
      raw: true
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;File.stream!/3&lt;/code&gt; function returns &lt;code&gt;%File.Stream{}&lt;/code&gt; with intended specifications.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-02/file-stream.png&quot; alt=&quot;File.stream&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The observer doesn&amp;#39;t reflect our CSV file&amp;#39;s extra memory size, meaning the file still needs to be opened and loaded into memory.&lt;/p&gt;
&lt;p&gt;Streams are composable enumerables. We can pipe one stream to another. We will replace the Enum functions from steps 2-4 of the greedy approach with stream functions. We&amp;#39;ll avoid processing data and loading it into memory until we decide to run the stream (compute/process the data as intended) by passing it to a function in the Enum module.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s compose our first part of the pipeline with streams:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; header = [:index, :org_id, :name, :website, :country, :description, :founded, :industry, :number_of_employees]
iex &amp;gt;
&amp;quot;/org.csv&amp;quot;
|&amp;gt; File.Stream!()
|&amp;gt; Stream.drop(1)
|&amp;gt; Stream.map(&amp;amp;String.split(&amp;amp;1, [&amp;quot;\n&amp;quot;, &amp;quot;,&amp;quot;], trim: true))
|&amp;gt; Stream.map(&amp;amp;Stream.zip(header, &amp;amp;1))
|&amp;gt; Stream.map(&amp;amp;(Map.new(&amp;amp;1)))

  #Stream&amp;lt;[
  enum: %File.Stream{
    path:  &amp;quot;/org.csv&amp;quot;,
    modes: [:raw, :read_ahead, :binary],
    line_or_bytes: :line,
    raw: true,
    node: :nonode@nohost
  },
  funs: [#Function&amp;lt;34.53678557/1 in Stream.drop/2&amp;gt;,
   #Function&amp;lt;48.53678557/1 in Stream.map/2&amp;gt;,
   #Function&amp;lt;48.53678557/1 in Stream.map/2&amp;gt;,
   #Function&amp;lt;48.53678557/1 in Stream.map/2&amp;gt;]
]&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The composed pipeline of streams above returns a stream that only stores the intended computation instead of applying the transformation.&lt;/p&gt;
&lt;p&gt;Here is what is happening within our stream processing pipeline:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of opening the file, we use &lt;code&gt;File.Stream/3&lt;/code&gt; to create a stream.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/1.15/Stream.html#drop/2&quot;&gt;Stream.drop/2&lt;/a&gt; lazily drops the first element, the header.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/1.15/Stream.html#map/2&quot;&gt;Stream.map/2&lt;/a&gt;:&lt;ul&gt;
&lt;li&gt;splits data into columns&lt;/li&gt;
&lt;li&gt;lazily zips each row into its corresponding header name with &lt;a href=&quot;https://hexdocs.pm/elixir/1.15/Stream.html#zip/2&quot;&gt;Stream.zip/2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;transforms each piece of data into a map&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To process our desired result, we have to pass the stream value to a function in the Enum module.
First, let&amp;#39;s take only the first 3 elements from our stream and observe what happens.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; csv
     |&amp;gt; File.stream!()
     |&amp;gt; Stream.drop(1)
     |&amp;gt; Stream.map(&amp;amp;String.split(&amp;amp;1, [&amp;quot;\n&amp;quot;, &amp;quot;,&amp;quot;], trim: true))
     |&amp;gt; Stream.map(&amp;amp;Stream.zip(header, &amp;amp;1))
     |&amp;gt; Stream.map(&amp;amp;(Map.new(&amp;amp;1)|&amp;gt; IO.inspect(label: &amp;quot;=============&amp;quot;)))
     |&amp;gt; Enum.take(3)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/Enum.html#take/2&quot;&gt;Enum.take/2&lt;/a&gt; receives the transformed map data from the stream and only gets the first 3 elements. Once it gets the 3 elements from the stream, there is no more processing.&lt;/p&gt;
&lt;p&gt;Running this pipeline, you will notice that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The result is returned instantaneously.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IO.inspect&lt;/code&gt; only prints the first 3 elements. This is proof that the elements are being processed one at a time by subsequent calls to Enum functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Lazy Approach Using Streams Vs. Greedy Approach&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s use the greedy approach to take the first 3 elements from our code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt;
[_| rows ] =
  csv
 |&amp;gt;  File.read!()
 |&amp;gt;  String.split(&amp;quot;\n&amp;quot;)
 |&amp;gt; Enum.map(&amp;amp;String.split(&amp;amp;1, &amp;quot;,&amp;quot;))


iex &amp;gt;
   rows
|&amp;gt; Enum.map(fn record -&amp;gt;  Enum.zip([:org_id, :name, :website, :country, :description, :founded, :industry, :number_of_employees], record) end)
|&amp;gt; Enum.map(fn record -&amp;gt; Map.new(record) |&amp;gt; IO.inspect(label: &amp;quot;+++++++++++++++++&amp;quot;) end)
|&amp;gt; Enum.take(3)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;IO.inspect&lt;/code&gt; prints the whole 2,000,000 records. This shows that with Enum, we have to wait for the whole collection to be available upfront before starting the next processing batch. Using this approach, an intermediate list of 2,000,000 records has to be kept in memory at each step (even if, in the end, we only get the first 3 records using &lt;code&gt;Enum.take/2&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Unlike the greedy approach, using the lazy approach, there is no need to process the whole collection for the next process to take place. By passing &lt;code&gt;Enum.take/2&lt;/code&gt; to fetch the first 3 elements, we can see there isn&amp;#39;t even a peak in memory.&lt;/p&gt;
&lt;p&gt;With streams, even if we process 2,000,000 records, we can decide the amount of records to load in memory and ensure that the amount of utilized memory stores the final result. This is not the same case with Enum, since in each step there is a certain amount of records kept in memory.&lt;/p&gt;
&lt;p&gt;We can also compare the greedy and lazy approaches by monitoring memory allocators using the Erlang observer.&lt;/p&gt;
&lt;p&gt;Remember, in the greedy approach, we processed all records. We will do the same with our lazy approach by passing the stream pipeline to &lt;a href=&quot;https://hexdocs.pm/elixir/Enum.html#to_list/1&quot;&gt;Enum.to_list/1&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex &amp;gt; csv
     |&amp;gt; File.stream!()
     |&amp;gt; Stream.drop(1)
     |&amp;gt; Stream.map(&amp;amp;String.split(&amp;amp;1, [&amp;quot;\n&amp;quot;, &amp;quot;,&amp;quot;], trim: true))
     |&amp;gt; Stream.map(&amp;amp;Stream.zip(header, &amp;amp;1))
     |&amp;gt; Stream.map(&amp;amp;(Map.new(&amp;amp;1)|&amp;gt; IO.inspect(label: &amp;quot;=============&amp;quot;)))
     |&amp;gt; Enum.to_list()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s the memory allocated to the lazy approach:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-02/lazy-approach.png&quot; alt=&quot;Lazy Approach&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And to the greedy approach:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-02/greedy-approach-final-step.png&quot; alt=&quot;step 4 greedy approach&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;In this post, we first took a look at collections in Elixir and some of their associated challenges. We then explored two methods of processing large datasets: the greedy approach and the lazy approach using streams.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ve seen how working with streams is one of the best approaches to help create a memory-efficient Elixir application.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Build A Simple Tracing System in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2024/01/23/build-a-simple-tracing-system-in-elixir.html"/>
    <id>https://blog.appsignal.com/2024/01/23/build-a-simple-tracing-system-in-elixir.html</id>
    <published>2024-01-23T00:00:00+00:00</published>
    <updated>2024-01-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s add tracing to an Elixir application using OpenTelemetry and streamline the process.</summary>
    <content type="html">&lt;p&gt;In this post, we&amp;#39;ll cover how Elixir applications can be traced using
OpenTelemetry and how macros can make this process super
easy and streamlined.&lt;/p&gt;
&lt;p&gt;First, we&amp;#39;ll talk about tracing and OpenTelemetry in Elixir. Then we&amp;#39;ll improve our custom tracing layer step-by-step until we get an easy
and seamless tool to trace our application.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;On Tracing in Elixir&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; All the research done to write this article resulted in the creation of the
&lt;a href=&quot;https://github.com/msramos/abstracing&quot;&gt;abstracing&lt;/a&gt; library. It&amp;#39;s far from
complete, but it encapsulates all the ideas written here.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Think of instances when your app crashes in production.
A bunch of artifacts are generated: stacktraces, logs, reports,
etc.&lt;/p&gt;
&lt;p&gt;When using proper &lt;a href=&quot;https://en.wikipedia.org/wiki/Tracing_(software)&quot;&gt;tracing&lt;/a&gt;,
developers can link all these artifacts in a sequence of events — from a starting
point down to the response, and operations with side effects.&lt;/p&gt;
&lt;p&gt;Here is a simple example of a &lt;code&gt;POST /users&lt;/code&gt; trace request:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2024-01/tracing-1.png&quot; alt=&quot;POST users trace&quot;/&gt;&lt;/p&gt;
&lt;p&gt;From left to right, we can see that the request was received, decoded,
validated, saved, and then, finally, a response was encoded and sent. Each little
block in this trace is called a &lt;strong&gt;span&lt;/strong&gt;. Spans are the building blocks of
tracing, as they represent events inside an application.&lt;/p&gt;
&lt;p&gt;Spans require this basic information: the start, the end, and the
status (success or error). We can enrich each span with more data, and they can even have a direct
correlation to these entities if we add
the appropriate metadata to logs and errors.&lt;/p&gt;
&lt;h2&gt;Meet OpenTelemetry for Elixir&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://opentelemetry.io/&quot;&gt;OpenTelemetry project homepage&lt;/a&gt; states that it is a:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Collection of APIs, SDKs, and tools&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That can be used to:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Instrument,
generate, collect, and export telemetry data (metrics, logs, and traces)&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For
Elixir, the
&lt;a href=&quot;https://github.com/open-telemetry/opentelemetry-erlang&quot;&gt;&lt;code&gt;OpenTelemetry&lt;/code&gt;&lt;/a&gt;
library has everything we need to perform distributed tracing.&lt;/p&gt;
&lt;p&gt;Here is a very simple example of how we can use it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# example.ex
defmodule Example do
  require OpenTelemetry.Tracer

  def some_fun() do
    OpenTelemetry.Tracer.with_span &amp;quot;example.some_fun&amp;quot; do
      # ...
      OpenTelemetry.Tracer.set_attribute(&amp;quot;key&amp;quot;, &amp;quot;value&amp;quot;)
      # ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;What&amp;#39;s Happening Here?&lt;/h3&gt;
&lt;p&gt;As you can see, it&amp;#39;s pretty straightforward. To start using all macros inside
&lt;code&gt;OpenTelemetry.Tracer&lt;/code&gt;, we first &lt;code&gt;require&lt;/code&gt; it at the top of our module.&lt;/p&gt;
&lt;p&gt;When we
want to start a span, we just need to call &lt;code&gt;OpenTelemetry.Tracer.with_span/2&lt;/code&gt;
and write our code.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Under the hood, &lt;code&gt;:otel_tracer.with_span/4&lt;/code&gt; is used to
actually start the span — even though the OpenTelemetry API does provide Elixir
modules to interact with, all the heavy lifting is actually written in Erlang.&lt;/p&gt;
&lt;p&gt;One really cool thing about spans is that we can add metadata to
reported data. This gives us more contextual information to investigate issues. We
can do this by calling &lt;code&gt;OpenTelemetry.Tracer.set_attribute/2&lt;/code&gt;. It only accepts a
small set of types (atoms, booleans, binaries, and tuples), so we need to be
mindful when using it.&lt;/p&gt;
&lt;p&gt;Now for a brief overview of how I ended up building an abstraction layer for OpenTelemetry.&lt;/p&gt;
&lt;h3&gt;Why I Built an Abstraction Layer for OpenTelemetry&lt;/h3&gt;
&lt;p&gt;When I first started using OpenTelemetry, I noticed that I was constantly creating small
private functions to translate data and help me with the setup. As I did
more and more of that, I eventually extracted all this boilerplate to its own
feature. I created an abstraction layer for OpenTelemetry.&lt;/p&gt;
&lt;p&gt;A few pain points during my use of OpenTelemetry that were solved by this
abstraction layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If your code throws an unexpected exception, the span will not be collected.&lt;/li&gt;
&lt;li&gt;Adding complex data requires transforming it first.&lt;/li&gt;
&lt;li&gt;Long namespaces (not really a problem, but I just don&amp;#39;t like them 😁).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Luckily, the OpenTelemetry library also has a low-level API that can be used to customize our tracing tooling, and that&amp;#39;s exactly what we&amp;#39;ll be doing now!&lt;/p&gt;
&lt;h2&gt;Breaking Down the Pain Points of OpenTelemetry&lt;/h2&gt;
&lt;p&gt;Now that we know some of the direct pain points of using OpenTelemetry, let&amp;#39;s
break them down into separate categories and solve each one. We can group the
features that we inject boilerplate code in to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setup: how we prepare a module to be traced&lt;/li&gt;
&lt;li&gt;Start/stop spans: the steps required to actually create spans&lt;/li&gt;
&lt;li&gt;Modifying spans: adding more attributes to spans&lt;/li&gt;
&lt;li&gt;Exception handling: collecting errors and changing the span status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end, we want to cover all these features with the &lt;em&gt;least&lt;/em&gt; amount
of boilerplate code as possible.&lt;/p&gt;
&lt;h2&gt;A Setup for a Setup in Elixir&lt;/h2&gt;
&lt;p&gt;The very first thing we need to do is prepare our module to use the tracing
macros and libraries. We&amp;#39;ll use Elixir&amp;#39;s special macro
&lt;a href=&quot;http://elixir-br.github.io/getting-started/alias-require-and-import.html#use&quot;&gt;&lt;code&gt;__using__/1&lt;/code&gt;&lt;/a&gt;
to automate some of this stuff for us:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/tracing.ex
# ...
defmacro __using__(_opts) do
  quote do
    require OpenTelemetry.Tracer

    require unquote(__MODULE__)
    import unquote(__MODULE__), only: [span: 1, span: 2, span: 3]
  end
end
# ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, whenever we need to trace our code, we just need to call &lt;code&gt;use Tracing&lt;/code&gt; at
the top of our module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyModule do
  use Tracing
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far, so good — but nothing too exciting. However, by using this simple setup
macro we don&amp;#39;t have to modify the modules using it if
we ever make changes to the setup process, as all changes will be automatically
replicated. That&amp;#39;s a good start!&lt;/p&gt;
&lt;p&gt;In the next section, we&amp;#39;ll start to remove some more meaningful boilerplate.&lt;/p&gt;
&lt;h2&gt;Translating Elixir Application Data to Span Attributes&lt;/h2&gt;
&lt;p&gt;OpenTelemetry allows applications to include attributes in spans. An attribute
consists of a &lt;code&gt;key&lt;/code&gt; and a &lt;code&gt;value&lt;/code&gt;. This helps us to include useful information
that can later be used to either create monitoring triggers or investigate
a crash.&lt;/p&gt;
&lt;p&gt;But here is a catch: OpenTelemetry only accepts numbers, strings, atoms,
booleans, and lists (if its elements are from any of the supported basic types).
Applications work with a richer set of data types: not only numbers and strings
but also complex &lt;code&gt;lists&lt;/code&gt;, &lt;code&gt;maps&lt;/code&gt;, &lt;code&gt;structs&lt;/code&gt;, and &lt;code&gt;tuples&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course, we can use &lt;code&gt;inspect/1&lt;/code&gt; on the variable values and have everything in
there. However, this makes searching for spans a much harder task, as we would need
to use complex regexes to search for them.&lt;/p&gt;
&lt;h3&gt;Convert Complex Types to Basic Types&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s possible, however, to convert the complex types to more basic (and
supported) types. Let&amp;#39;s define a few rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lists will use their indexes to name the values&lt;/li&gt;
&lt;li&gt;Tuples will be converted to lists&lt;/li&gt;
&lt;li&gt;Maps will use their keys to name values&lt;/li&gt;
&lt;li&gt;Structs will be converted to maps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, a simple list like &lt;code&gt;[1, 2, 3]&lt;/code&gt; would be transformed into a list of pairs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;my_list = [1, 2, 3]
Tracing.set_attribute(&amp;quot;numbers&amp;quot;, my_list)
# numbers.0 = 1
# numbers.1 = 2
# numbers.2 = 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For maps, we can use their keys to generate the pairs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;my_map = %{first_name: &amp;quot;John&amp;quot;, last_name: &amp;quot;Wick&amp;quot;}
Tracing.set_attribute(&amp;quot;user&amp;quot;, my_map)
# user.first_name = &amp;quot;John&amp;quot;
# user.last_name = &amp;quot;Wick&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Using Elixir&amp;#39;s &lt;code&gt;defguard&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Since we&amp;#39;re handling maps, lists, and tuples as a set of values, we can use
Elixir&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/elixir/1.15.4/Kernel.html#defguard/1&quot;&gt;&lt;code&gt;defguard&lt;/code&gt;&lt;/a&gt;
to create a custom function guard:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/tracing.ex
defmodule Tracing do
  # ...
  defguard is_set(value) when is_map(value) or is_list(value) or is_tuple(value)
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can start building our custom &lt;code&gt;set_attribute&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/tracing.ex
defmodule Tracing do
  # ...
  def set_attribute(key, value) when is_set(value) do
    set_attributes(key, value) # To be yet defined!
  end

  def set_attribute(key, value) do
    OpenTelemetry.Tracer.set_attribute(key, value)
  end
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s simple: if the value is a set, we call &lt;code&gt;set_attributes&lt;/code&gt; (in plural!),
otherwise, we just delegate to &lt;code&gt;OpenTelemety.Tracer.set_attribute/2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The next piece is where all the transformation happens:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/tracing.ex
defmodule Tracing do
  # ...
  def set_attributes(key, values) do
    key
    |&amp;gt; enumerable_to_attrs(values) # To be yet defined!
    |&amp;gt; OpenTelemetry.Tracer.set_attributes()
  end
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we receive the set of values, convert them, and then call
&lt;code&gt;OpenTelemetry.Tracer.set_attributes/1&lt;/code&gt; to do the actual work of adding the
attributes to the span.&lt;/p&gt;
&lt;p&gt;The data conversion happens in the
&lt;a href=&quot;https://github.com/msramos/abstracing/blob/d3fd435fa275c16f247e17d99a79fcc3fce7ef31/lib/tracing.ex#L428-L474&quot;&gt;&lt;code&gt;enumerable_to_attrs/2&lt;/code&gt;&lt;/a&gt;
function. It works by recursively going into each element of the collection and
converting it to the appropriate basic type supported by OpenTelemetry. Adding
its code here is beyond the scope of this post, but feel free to &lt;a href=&quot;https://github.com/msramos/abstracing/blob/d3fd435fa275c16f247e17d99a79fcc3fce7ef31/lib/tracing.ex#L428-L474&quot;&gt;check
it out on GitHub&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we discussed the basics of tracing and began to explore how
we can utilize OpenTelemetry in Elixir. We laid the foundation for an
abstraction layer that will simplify the creation and manipulation of spans,
making the process seamless and straightforward.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>AppSignal’s Top 5 Elixir Posts in 2023</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/12/20/appsignals-top-5-elixir-posts-in-2023.html"/>
    <id>https://blog.appsignal.com/2023/12/20/appsignals-top-5-elixir-posts-in-2023.html</id>
    <published>2023-12-20T00:00:00+00:00</published>
    <updated>2023-12-20T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">It&#039;s time for our yearly rundown of our top 5 best-performing Elixir posts.</summary>
    <content type="html">&lt;p&gt;As the year draws to an end, we&amp;#39;re excited to share our top five most-read Elixir articles in 2023!&lt;/p&gt;
&lt;h2&gt;Top 5 Elixir Blog Posts in 2023 ⚗️&lt;/h2&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2023/02/28/an-introduction-to-test-factories-and-fixtures-for-elixir.html&quot;&gt;An Introduction to Test Factories and Fixtures for Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the first part of this three-part series, we give an overview of Elixir test factories and fixtures.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2023/02/14/under-the-hood-of-ecto.html&quot;&gt;Under the Hood of Ecto&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Explore how Ecto&amp;#39;s internals work by looking at its four major modules in detail.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2023/06/06/absinthe-for-large-elixir-applications.html&quot;&gt;Absinthe for Large Elixir Applications&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Discover how you can best use Absinthe for data-heavy Elixir applications.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2023/11/07/validating-data-in-elixir-using-ecto-and-nimbleoptions.html&quot;&gt;Validating Data in Elixir: Using Ecto and NimbleOptions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We dive into how to avoid bad data using Ecto and NimbleOptions in the second part of our Validating Data at the Boundary series.&lt;/p&gt;
&lt;p&gt;Finally, here&amp;#39;s our top Elixir post in 2023!&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.appsignal.com/2023/09/12/phoenix-1-7-for-elixir-edit-a-form-in-a-modal.html&quot;&gt;Phoenix 1.7 for Elixir: Edit a Form in a Modal&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the third part of our Modal Forms and LiveView in Phoenix 1.7 series, we implement an edit modal.&lt;/p&gt;
&lt;h2&gt;Season&amp;#39;s Greetings ❆ ⛄&lt;/h2&gt;
&lt;p&gt;Have a wonderful festive break, and we&amp;#39;ll see you in the new year!&lt;/p&gt;
&lt;p&gt;If you haven’t already, don’t forget to &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter&lt;/a&gt;, so you never miss an upcoming post.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>What&#039;s New in Elixir 1.16</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/12/19/whats-new-in-elixir-1-16.html"/>
    <id>https://blog.appsignal.com/2023/12/19/whats-new-in-elixir-1-16.html</id>
    <published>2023-12-19T00:00:00+00:00</published>
    <updated>2023-12-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s explore the new features and improvements in Elixir 1.16.</summary>
    <content type="html">&lt;p&gt;The &lt;a href=&quot;https://github.com/elixir-lang/elixir/releases/tag/v1.16.0-rc.1&quot;&gt;Elixir 1.16 release candidate&lt;/a&gt; is out now, and it comes with some compelling improvements to diagnostics, documentation, and a few other enhancements that make Elixir an even better choice for developers.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll dive into some of these changes and highlight Elixir&amp;#39;s continued focus on developer happiness and community building.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Better Diagnostics for Compiler Errors in Elixir&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll begin with the improvements to compiler diagnostics provided in Elixir 1.16. Now, your &lt;code&gt;mix compile&lt;/code&gt; errors come with detailed code snippets that tell you exactly where your code goes wrong.&lt;/p&gt;
&lt;p&gt;You&amp;#39;ll benefit from these improvements when you have syntax errors, mismatched delimiter errors, and generic compiler errors.&lt;/p&gt;
&lt;h3&gt;Syntax Errors&lt;/h3&gt;
&lt;p&gt;First up, you can see below that syntax errors now come with a pointer to exactly where the error happened. Let&amp;#39;s say we have the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Doctor do
  def show_prescription_codes do
    [&amp;quot;DR&amp;quot;, &amp;quot;DS&amp;quot;, &amp;quot;amp&amp;quot;, &amp;amp;]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you run &lt;code&gt;mix compile&lt;/code&gt;, you&amp;#39;ll see a syntax error with an associated code snippet, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sophiedebenedetto[ 7:30PM] ~/personal-projects/doctor  💖 mix compile
Compiling 1 file (.ex)

== Compilation error in file lib/doctor.ex ==
** (SyntaxError) invalid syntax found on lib/doctor.ex:48:26:
    error: syntax error before: &amp;#39;]&amp;#39;
    │
 48 │     [&amp;quot;DR&amp;quot;, &amp;quot;DS&amp;quot;, &amp;quot;amp&amp;quot;, &amp;amp;]
    │                          ^
    │
    └─ lib/doctor.ex:48:26
    (elixir 1.16.0-rc.1) lib/kernel/parallel_compiler.ex:428: anonymous fn/5 in Kernel.ParallelCompiler.spawn_workers/8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;code&gt;^&lt;/code&gt; pointer to the exact location of the syntax error. With this, it&amp;#39;s even easier to quickly spot and correct such errors.&lt;/p&gt;
&lt;h3&gt;Mismatched Delimiter Errors&lt;/h3&gt;
&lt;p&gt;Another diagnostic improvement comes with the code snippet representation for &lt;code&gt;MismatchedDelimiterError&lt;/code&gt; occurrences. Given the following code with a mismatched delimiter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Doctor do
  def show_prescription_codes do
    [&amp;quot;DR&amp;quot;, &amp;quot;DS&amp;quot;, &amp;quot;amp&amp;quot;, &amp;quot;ad&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running &lt;code&gt;mix compile&lt;/code&gt; will now show you the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sophiedebenedetto[ 7:29PM] ~/personal-projects/doctor  💖 mix compile
Compiling 1 file (.ex)

== Compilation error in file lib/doctor.ex ==
** (MismatchedDelimiterError) mismatched delimiter found on lib/doctor.ex:48:29:
    error: unexpected token: )
    │
 48 │     [&amp;quot;DR&amp;quot;, &amp;quot;DS&amp;quot;, &amp;quot;amp&amp;quot;, &amp;quot;ad&amp;quot;)
    │     │                       └ mismatched closing delimiter (expected &amp;quot;]&amp;quot;)
    │     └ unclosed delimiter
    │
    └─ lib/doctor.ex:48:29
    (elixir 1.16.0-rc.1) lib/kernel/parallel_compiler.ex:428: anonymous fn/5 in Kernel.ParallelCompiler.spawn_workers/8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This error includes a display of the code snippet that is causing it, and even highlights the unclosed and mismatched delimiters associated to the &lt;code&gt;MismatchedDelimiterError&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Other Errors&lt;/h3&gt;
&lt;p&gt;You&amp;#39;ll now see similarly detailed code snippets for all kinds of compiler errors, including errors that describe undefined variables. Let&amp;#39;s look at an example of that now.&lt;/p&gt;
&lt;p&gt;Given the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def list_patients do
  Patient.for_doctor(doctor)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running &lt;code&gt;mix compile&lt;/code&gt; will display the following error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sophiedebenedetto[ 7:36PM] ~/personal-projects/doctor  💖 mix compile
Compiling 1 file (.ex)
    error: undefined variable &amp;quot;doctor&amp;quot;
    │
 53 │     Patient.for_doctor(doctor)
    │                        ^^^^^^
    │
    └─ lib/doctor.ex:53:24: Doctor.list_patients/0


== Compilation error in file lib/doctor.ex ==
** (CompileError) lib/doctor.ex: cannot compile module Doctor (errors have been logged)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These improved diagnostics make it even easier for Elixir developers to understand compilation errors, catch and remedy basic mistakes, and write clean and functioning code. These improvements show Elixir&amp;#39;s continued focus on developer experience.&lt;/p&gt;
&lt;h2&gt;ExDoc Content Matures with Elixir&lt;/h2&gt;
&lt;p&gt;Some of the most exciting changes coming in Elixir 1.16 are the improvements to official Elixir language docs, offered through ExDoc. The &amp;quot;Getting Started&amp;quot; guide from &lt;a href=&quot;https://elixir-lang.org/docs.html&quot;&gt;elixir-lang.org&lt;/a&gt; has been incorporated into the &lt;a href=&quot;https://hexdocs.pm/elixir/1.16/introduction.html&quot;&gt;official Elixir documentation on Hex docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While this may not seem too exciting on the surface, it represents a concerted effort to refine and unify official guidance on the Elixir programming language. The language and the community have matured to such a stage that we can better align on official guides like this and provide the best agreed-upon direction for new developers.&lt;/p&gt;
&lt;h3&gt;Anti-Patterns&lt;/h3&gt;
&lt;p&gt;In this same vein, the official Elixir docs now include robust content on &lt;a href=&quot;https://hexdocs.pm/elixir/1.16.0-rc.1/what-anti-patterns.html&quot;&gt;Elixir anti-patterns&lt;/a&gt;. This content is divided into four separate sections, covering code, design, processes, and metaprogramming.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12/anti-patterns.png&quot; alt=&quot;Anti-patterns documentation in Elixir&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Once again, this content is made possible by the maturity of the Elixir language. As Elixir has grown up, and as adoption and the community have grown, we&amp;#39;re at a point where Elixir developers can align on what good and bad Elixir code looks like.&lt;/p&gt;
&lt;p&gt;With this extensive guidance in the official docs, including framing context and code samples, Elixir developers have the resources they need to ship clean code that meets generally agreed-upon standards. It will be even easier for experienced and novice Elixir developers alike to write and maintain clean code in various scenarios.&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s not it for docs enhancements.&lt;/p&gt;
&lt;h3&gt;ExDoc Cheatsheets In the Official Elixir Docs&lt;/h3&gt;
&lt;p&gt;The official docs now include an ExDoc cheatsheet for the first time. ExDoc &lt;a href=&quot;https://elixir-lang.org/blog/2022/12/22/cheatsheets-and-8-other-features-in-exdoc-that-improve-the-developer-experience/&quot;&gt;cheatsheets&lt;/a&gt; allow developers to author quick, summary-type guides to modules and libraries.&lt;/p&gt;
&lt;p&gt;The official Elixir docs now include an &lt;a href=&quot;https://hexdocs.pm/elixir/main/enum-cheat.html&quot;&gt;Enum module cheatsheet&lt;/a&gt;, and that&amp;#39;s just the beginning.&lt;/p&gt;
&lt;p&gt;Elixir maintainers are looking for more community members to contribute cheatsheets to the official docs. This is a great way for first-timers to get an Elixir language contribution! Get started by opening an &lt;a href=&quot;https://github.com/elixir-lang/elixir/issues/new&quot;&gt;issue&lt;/a&gt; that outlines what cheatsheet you&amp;#39;d like to add.&lt;/p&gt;
&lt;p&gt;Taken together, these docs improvements all point to the maturity of the Elixir language and community and the continued focus on education and support for Elixir newcomers. The official introduction docs, the anti-pattern docs, and the inclusion of cheatsheets provide clear and accessible guidance to Elixir developers at every level. This kind of alignment and clarity makes Elixir even more accessible to novices. At the same time, it empowers experienced Elixir devs to deliver clean, standardized Elixir code that performs well.&lt;/p&gt;
&lt;h2&gt;More Enhancements&lt;/h2&gt;
&lt;p&gt;You might be interested in taking advantage of some of the smaller enhancements from this release in your upgraded Elixir apps. Let&amp;#39;s explore them briefly now.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;String.replace_invalid/2&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;First up, there is a new &lt;code&gt;String.replace_invalid/2&lt;/code&gt; function that (you guessed it) lets you replace invalid characters in a string. Let&amp;#39;s take a look at an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; String.replace_invalid(&amp;quot;asd&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFF::8&amp;gt;&amp;gt;)
&amp;quot;asd�&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The default behavior is to replace the invalid character with a &lt;code&gt;�&lt;/code&gt;, but you can replace it with any character you like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; String.replace_invalid(&amp;quot;asd&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFF::8&amp;gt;&amp;gt;, &amp;quot;😵&amp;quot;)
&amp;quot;asd😵&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will come in handy if you find yourself processing strings of text from external sources. Such text may contain invalid characters, and identifying and replacing such characters just got a lot easier.&lt;/p&gt;
&lt;h3&gt;New Functionality for &lt;code&gt;Task.yield_many/2&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Next up, let&amp;#39;s take a look at the new option you can pass to &lt;code&gt;Task.yield_many&lt;/code&gt;. Previously, you could tell &lt;code&gt;Task.yield_many&lt;/code&gt; to timeout and stop waiting for tasks if a certain time limit was exceeded. Now, you can provoke that same behavior if a certain &lt;em&gt;number&lt;/em&gt; of tasks has been reached. You can do so by providing the &lt;code&gt;limit&lt;/code&gt; option.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say you have the following code to spawn ten tasks. Each task will sleep for &lt;code&gt;i&lt;/code&gt; number of seconds and then return a message indicating what happened. Then, we yield each task with its result, and iterate over those &lt;code&gt;{task, result}&lt;/code&gt; tuples to operate on the result by &lt;code&gt;IO.inspect&lt;/code&gt;-ing them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def MyModule do
  def do_tasks do
    tasks =
      for i &amp;lt;- 1..10 do
        Task.async(fn -&amp;gt;
          Process.sleep(i * 1000)
          &amp;quot;I slept for #{i} seconds&amp;quot;
        end)
      end

    tasks_with_results = Task.yield_many(tasks, timeout: 10000)

    results =
      Enum.map(tasks_with_results, fn {task, res} -&amp;gt;
        # Shut down the tasks that did not reply nor exit
        res || Task.shutdown(task, :brutal_kill)
      end)

    # Here we are matching only on {:ok, value} and
    # ignoring {:exit, _} (crashed tasks) and `nil` (no replies)
    for {:ok, value} &amp;lt;- results do
      IO.inspect(value)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will continue to yield tasks and their results until all the tasks are done &lt;em&gt;or&lt;/em&gt; the timeout is exceeded. Now, you can use the &lt;code&gt;limit: task_num&lt;/code&gt; option instead of &lt;code&gt;timeout&lt;/code&gt;, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;tasks_with_results = Task.yield_many(tasks, limit: 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we execute our function in IEx, you&amp;#39;ll see that the code stops waiting for tasks after just one task is yielded:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; MyModule.do_tasks()
&amp;quot;I slept for 1 seconds&amp;quot;
[&amp;quot;I slept for 1 seconds&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the limit is reached before the default timeout (&lt;code&gt;5000&lt;/code&gt;), or before all the tasks are done, then &lt;code&gt;Task.yield_many&lt;/code&gt; returns immediately without triggering the &lt;code&gt;:on_timeout&lt;/code&gt; behaviour. You can dig further into this functionality in &lt;a href=&quot;https://hexdocs.pm/elixir/1.16.0-rc.1/Task.html#yield_many/2&quot;&gt;the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This new functionality gives you even more fine-grained control over how your program orchestrates async tasks.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;Logger.levels/0&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;The last enhancement I&amp;#39;ll highlight here is the new &lt;code&gt;Logger.levels/0&lt;/code&gt; function. This function returns the list of all available log levels:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Logger.levels()
[:error, :info, :debug, :emergency, :alert, :critical, :warning, :notice]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This provides a quick reminder of the levels you can use to configure your logger.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;With the 1.16 release, Elixir continues to be a compelling choice for developers looking for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An excellent developer experience&lt;/li&gt;
&lt;li&gt;A welcoming and supportive community&lt;/li&gt;
&lt;li&gt;Strong and opinionated development guidelines&lt;/li&gt;
&lt;li&gt;Powerful language capabilities to meet the needs of various programming scenarios.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new developments in diagnostics, documentation, and language functionality continue to make Elixir a pleasure to work with. Better, more detailed diagnostic messages for compiler errors show Elixir&amp;#39;s emphasis on developer experience, making it easier than ever before to identify and fix these errors.&lt;/p&gt;
&lt;p&gt;Improved docs and the addition of the anti-patterns guide empowers both experienced &lt;em&gt;and&lt;/em&gt; newbie Elixir devs to write clean and standardized code. And minor language improvements, like the functions we explored above, show Elixir&amp;#39;s continued commitment to language excellence.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Advanced Multi-tenancy for Elixir Applications Using Ecto</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/12/05/advanced-multi-tenancy-for-elixir-applications-using-ecto.html"/>
    <id>https://blog.appsignal.com/2023/12/05/advanced-multi-tenancy-for-elixir-applications-using-ecto.html</id>
    <published>2023-12-05T00:00:00+00:00</published>
    <updated>2023-12-05T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of our series, we&#039;ll build on our multi-tenant Phoenix application using Ecto custom types and other methods.</summary>
    <content type="html">&lt;p&gt;Welcome to part two of this series. In the previous tutorial, we learned about multi-tenancy, including different multi-tenancy implementation strategies. We also started building a multi-tenant Phoenix link shortening app and added basic user authentication.&lt;/p&gt;
&lt;p&gt;In this final part of the series, we&amp;#39;ll build the link resource, associate users to links, and set up the redirect functionality in our app. As we finalize the app build, we&amp;#39;ll learn about features (like Ecto custom types) that make Phoenix such a powerful framework for Elixir.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s now turn our attention to link shortening.&lt;/p&gt;
&lt;h2&gt;Adding &lt;code&gt;Link&lt;/code&gt; Resources&lt;/h2&gt;
&lt;p&gt;As a reminder, here&amp;#39;s how link shortening will happen in our app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Logged-in user enters a long URL&lt;/li&gt;
&lt;li&gt;A random string is generated and associated with the long URL&lt;/li&gt;
&lt;li&gt;Whenever this short URL is visited, the app will keep a tally of the number of visits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;#39;ll get started by generating a controller, schema, migration, and views for a &lt;code&gt;Link&lt;/code&gt; resource:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix phx.gen.html Links Link links url:string visits:integer account_id:references:accounts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should generate most of the boilerplate code we need to work with the &lt;code&gt;Link&lt;/code&gt; resource.&lt;/p&gt;
&lt;p&gt;You may notice that we haven&amp;#39;t included a field for the short random string referencing the long URL. We&amp;#39;ll cover this next.&lt;/p&gt;
&lt;h2&gt;Creating Short URLs Using the Ecto Custom Type in Phoenix&lt;/h2&gt;
&lt;p&gt;By default, Ecto models have an &lt;code&gt;id&lt;/code&gt; field used as a model&amp;#39;s primary key. Usually, it&amp;#39;s in the form of an integer or, in some cases, a &lt;a href=&quot;https://hexdocs.pm/ecto/0.13.0/Ecto.Schema.html&quot;&gt;binary ID&lt;/a&gt;. In either case, when present in a model, this field is automatically incremented for every additional model created in an app.&lt;/p&gt;
&lt;p&gt;A core function of our app is generating short, unique strings to represent long URLs. We could write a custom function to generate such strings, but since we are on a quest to learn Elixir, let&amp;#39;s use a more creative approach.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s substitute the &lt;code&gt;id&lt;/code&gt; primary key in the &lt;code&gt;Link&lt;/code&gt; model with a custom &lt;a href=&quot;https://elixir-lang.org/getting-started/typespecs-and-behaviours.html&quot;&gt;Ecto type&lt;/a&gt; called &lt;code&gt;HashId&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Using this approach, we&amp;#39;ll:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn how to create and use Elixir custom types.&lt;/li&gt;
&lt;li&gt;Automatically generate unique string hashes to form the short URL field for links. Ecto will manage the process whenever a new link model is created.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;First, create a new file to represent this new type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/ecto/hash_id.ex

defmodule Urlbot.Ecto.HashId do
  @behaviour Ecto.Type
  @hash_id_length 8

  # Called when creating an Ecto.Changeset
  @spec cast(any) :: Map.t
  def cast(value), do: hash_id_format(value)

  # Accepts a value that has been directly placed into the ecto struct after a changeset
  @spec dump(any) :: Map.t
  def dump(value), do: hash_id_format(value)

  # Changes a value from the default type into the HashId type
  @spec load(any) :: Map.t
  def load(value), do: hash_id_format(value)

  # A callback invoked by autogenerate fields
  @spec autogenerate() :: String.t
  def autogenerate, do: generate()

 # The Ecto type that is being converted
  def type, do: :string

  @spec hash_id_format(any) :: Map.t
  def hash_id_format(value) do
    case validate_hash_id(value) do
      true -&amp;gt; {:ok, value}
      _ -&amp;gt; {:error, &amp;quot;&amp;#39;#{value}&amp;#39; is not a string&amp;quot;}
    end
  end

  # Validation of given value to be of type &amp;quot;String&amp;quot;
  def validate_hash_id(string) when is_binary(string), do: true
  def validate_hash_id(_other), do: false

  # The function that generates a HashId
  @spec generate() :: String.t
  def generate do
    @hash_id_length
    |&amp;gt; :crypto.strong_rand_bytes()
    |&amp;gt; Base.url_encode64
    |&amp;gt; binary_part(0, @hash_id_length)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://elixir-lang.org/getting-started/typespecs-and-behaviours.html&quot;&gt;Ecto custom types documentation&lt;/a&gt;, which covers the subject in a much more exhaustive way than we could in this tutorial.&lt;/p&gt;
&lt;p&gt;For now, what we&amp;#39;ve just done allows us to use the custom data type &lt;code&gt;HashId&lt;/code&gt; when defining a field&amp;#39;s data type.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s use this new data type to define the short URL field for the &lt;code&gt;Link&lt;/code&gt; resource next.&lt;/p&gt;
&lt;h2&gt;Using the Custom Ecto Type in Phoenix&lt;/h2&gt;
&lt;p&gt;Open up the &lt;code&gt;Link&lt;/code&gt; schema and edit it to reference the new Ecto type we&amp;#39;ve just defined:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/links/link.ex

defmodule Urlbot.Links.Link do
  use Ecto.Schema
  import Ecto.Changeset
  alias Urlbot.Ecto.HashId # Add this line

  @primary_key {:hash, HashId, [autogenerate: true]} # Add this line
  @derive {Phoenix.Param, key: :hash} # Add this line

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before moving on, let&amp;#39;s briefly explain the use of &lt;code&gt;@derive&lt;/code&gt; in the code above.&lt;/p&gt;
&lt;p&gt;In Elixir, a &lt;a href=&quot;https://hexdocs.pm/elixir/1.14/Protocol.html&quot;&gt;protocol&lt;/a&gt; defines an API and its specific implementations. &lt;a href=&quot;https://hexdocs.pm/phoenix/Phoenix.Param.html&quot;&gt;&lt;code&gt;Phoenix.Param&lt;/code&gt;&lt;/a&gt; is a protocol used to convert data structures into URL parameters. By default, this protocol is used for integers, binaries, atoms, and structs. The default key &lt;code&gt;:id&lt;/code&gt; is usually used for structs, but it&amp;#39;s possible to define other parameters. In our case, we use the parameter &lt;code&gt;hash&lt;/code&gt; and make its implementation derivable to actually use it.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s modify the links migration to use this new parameter type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# priv/repo/migrations/XXXXXX_create_links.exs

defmodule Urlbot.Repo.Migrations.CreateLinks do
  use Ecto.Migration

  def change do
    create table(:links, primary_key: false) do
      add :hash, :string, primary_key: true
      add :url, :string
      add :visits, :integer
      add :account_id, references(:accounts, on_delete: :delete_all)

      timestamps()
    end

    create index(:links, [:account_id])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run the migration to create the links table:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix ecto.migrate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now need to associate &lt;code&gt;Link&lt;/code&gt; and &lt;code&gt;Account&lt;/code&gt;— but before we do, let&amp;#39;s ensure that only an authenticated user can make CRUD operations for &lt;code&gt;Link&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Updating &lt;code&gt;Link&lt;/code&gt; Routes in Phoenix for Elixir&lt;/h2&gt;
&lt;p&gt;In the router, we need to create a new pipeline to process routes that only authenticated users can access.&lt;/p&gt;
&lt;p&gt;Go ahead and add this pipeline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot_web/router.ex

defmodule UrlbotWeb.Router do
  use UrlbotWeb, :router
  use Pow.Phoenix.Router

  ...

  pipeline :protected do
    plug Pow.Plug.RequireAuthenticated, error_handler: Pow.Phoenix.PlugErrorHandler
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add the scope to handle &lt;code&gt;Link&lt;/code&gt; routes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot_web/router.ex

defmodule UrlbotWeb.Router do
  use UrlbotWeb, :router
  use Pow.Phoenix.Router

  ...

  pipeline :protected do
    plug Pow.Plug.RequireAuthenticated, error_handler: Pow.Phoenix.PlugErrorHandler
  end

  scope &amp;quot;/&amp;quot;, UrlbotWeb do
    pipe_through [:protected, :browser]

    resources &amp;quot;/links&amp;quot;, LinkController
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if you try to access any of the protected routes, Pow should redirect you to a login page:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12/link-routes-protected.png&quot; alt=&quot;Trying to access a protected route&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Our app build is progressing well. Next, let&amp;#39;s associate &lt;code&gt;Link&lt;/code&gt; and &lt;code&gt;Account&lt;/code&gt; since this forms the basis of tenant separation in our app.&lt;/p&gt;
&lt;h2&gt;Assigning &lt;code&gt;Link&lt;/code&gt; to &lt;code&gt;Account&lt;/code&gt; in Elixir&lt;/h2&gt;
&lt;p&gt;Take a look at the &lt;code&gt;Link&lt;/code&gt; schema below. We want to make sure &lt;code&gt;account_id&lt;/code&gt; is included, since this will form the link to &lt;code&gt;Account&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/links/link.ex

defmodule Urlbot.Links.Link do
  use Ecto.Schema
  import Ecto.Changeset
  alias Urlbot.Ecto.HashId

  ...

  schema &amp;quot;links&amp;quot; do
    field :url, :string
    field :visits, :integer
    field :account_id, :id

    timestamps()
  end
  ...

end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Next, edit the changeset block, adding &lt;code&gt;account_id&lt;/code&gt; to the list of allowed attributes and those that will go through validation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/links/link.ex

defmodule Urlbot.Links.Link do
  use Ecto.Schema
  import Ecto.Changeset
  alias Urlbot.Ecto.HashId

  ...

  def changeset(link, attrs) do
    link
    |&amp;gt; cast(attrs, [:url, :visits, :account_id])
    |&amp;gt; validate_required([:url, :visits, :account_id])
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, edit the &lt;code&gt;Account&lt;/code&gt; schema and add a &lt;code&gt;has_many&lt;/code&gt; relation as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/accounts/account.ex

defmodule Urlbot.Accounts.Account do
  use Ecto.Schema
  import Ecto.Changeset
  alias Urlbot.Users.User
  alias Urlbot.Links.Link

  schema &amp;quot;accounts&amp;quot; do
    field :name, :string

    has_many :users, User
    has_many :links, Link # Add this line

    timestamps()
  end

  ...

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to edit the &lt;code&gt;Link&lt;/code&gt; context to work with &lt;code&gt;Account&lt;/code&gt;. Remember, scoping a resource to a user or account is the foundation of any multi-tenant structure.&lt;/p&gt;
&lt;p&gt;Edit your file as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/links.ex

defmodule Urlbot.Links do
  ...

  def list_links(account) do
    from(s in Link, where: s.account_id == ^account.id, order_by: [asc: :id])
    |&amp;gt; Repo.all()
  end

  def get_link!(account, id) do
    Repo.get_by!(Link, account_id: account.id, id: id)
  end

  def create_link(account, attrs \\ %{}) do
    Ecto.build_assoc(account, :links)
    |&amp;gt; Link.changeset(attrs)
    |&amp;gt; Repo.insert()
  end

  ...

end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Adding a &lt;code&gt;Current_Account&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Our edits to the &lt;code&gt;Link&lt;/code&gt; context show that most related controller methods use the &lt;code&gt;account&lt;/code&gt; variable. This variable needs to be extracted from the currently logged-in user&amp;#39;s &lt;code&gt;account_id&lt;/code&gt; and passed on to the respective controller action.&lt;/p&gt;
&lt;p&gt;So we need to make a custom plug to add to the &lt;code&gt;conn&lt;/code&gt;. Create a new file — &lt;code&gt;lib/plugs/set_current_account.ex&lt;/code&gt; — and edit its content as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/plugs/set_current_account.ex

defmodule UrlbotWeb.Plugs.SetCurrentAccount do
  import Plug.Conn
  alias Urlbot.Repo
  alias Urlbot.Users.User

  def init(options), do: options

  def call(conn, _opts) do
    case conn.assigns[:current_user] do
      %User{} = user -&amp;gt;
        %User{account: account} = Repo.preload(user, :account)
        assign(conn, :current_account, account)
      _ -&amp;gt;
        assign(conn, :current_account, nil)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let&amp;#39;s use this new plug by adding it to the router (specifically to the &lt;code&gt;protected&lt;/code&gt; pipeline since user sessions are handled there):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot_web/router.ex

defmodule UrlbotWeb.Router do
  use UrlbotWeb, :router
  use Pow.Phoenix.Router

  ...

  pipeline :protected do
    plug Pow.Plug.RequireAuthenticated, error_handler: Pow.Phoenix.PlugErrorHandler
    plug UrlbotWeb.Plugs.SetCurrentAccount # Add this line
  end

  ...

  scope &amp;quot;/&amp;quot;, UrlbotWeb do
    pipe_through [:protected, :browser]

    resources &amp;quot;/links&amp;quot;, LinkController
  end

  ...

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, edit the &lt;code&gt;Link&lt;/code&gt; controller to pass the &lt;code&gt;current_account&lt;/code&gt; in every action where it&amp;#39;s required, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot_web/controllers/link_controller.ex

defmodule UrlbotWeb.LinkController do
  use UrlbotWeb, :controller

  alias Urlbot.Links
  alias Urlbot.Links.Link

  def index(conn, _params) do
    current_account = conn.assigns.current_account  # Add this line
    links = Links.list_links(current_account)
    render(conn, :index, links: links)
  end
  def create(conn, %{&amp;quot;link&amp;quot; =&amp;gt; link_params}) do
    current_account = conn.assigns.current_account # Add this line
    case Links.create_link(current_account, link_params) do
      {:ok, link} -&amp;gt;
        conn
        |&amp;gt; put_flash(:info, &amp;quot;Link created successfully.&amp;quot;)
        |&amp;gt; redirect(to: ~p&amp;quot;/links&amp;quot;)

      {:error, %Ecto.Changeset{} = changeset} -&amp;gt;
        render(conn, :new, changeset: changeset)
    end
  end

  def edit(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}) do
    current_account = conn.assigns.current_account  # Add this line
    link = Links.get_link!(current_account, id)
    changeset = Links.change_link(link)
    render(conn, :edit, link: link, changeset: changeset)
  end

  def update(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id, &amp;quot;link&amp;quot; =&amp;gt; link_params}) do
    current_account = conn.assigns.current_account  # Add this line
    link = Links.get_link!(current_account, id)

    case Links.update_link(link, link_params) do
      {:ok, link} -&amp;gt;
        conn
        |&amp;gt; put_flash(:info, &amp;quot;Link updated successfully.&amp;quot;)
        |&amp;gt; redirect(to: ~p&amp;quot;/links/#{link}&amp;quot;)

      {:error, %Ecto.Changeset{} = changeset} -&amp;gt;
        render(conn, :edit, link: link, changeset: changeset)
    end
  end

  def delete(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}) do
    current_account = conn.assigns.current_account  # Add this line
    link = Links.get_link!(current_account, id)
    {:ok, _link} = Links.delete_link(link)

    conn
    |&amp;gt; put_flash(:info, &amp;quot;Link deleted successfully.&amp;quot;)
    |&amp;gt; redirect(to: ~p&amp;quot;/links&amp;quot;)
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s it! Now, any created &lt;code&gt;Link&lt;/code&gt; will be associated with a currently logged-in user&amp;#39;s account.&lt;/p&gt;
&lt;p&gt;At this point, we have everything we need for users to create links that are properly scoped to their respective accounts. You can see this in action when you consider the list index action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;
defmodule UrlbotWeb.LinkController do
  use UrlbotWeb, :controller

  alias Urlbot.Links
  alias Urlbot.Links.Link

  def index(conn, _params) do
    current_account = conn.assigns.current_account
    links = Links.list_links(current_account)
    render(conn, :index, links: links)
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, a user should only see links that are associated with them.&lt;/p&gt;
&lt;p&gt;For example, this is a list index view for one user:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12/user1s-links-index.png&quot; alt=&quot;First user&amp;#39;s link index view&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And this is a view for a different user (notice the logged-in user&amp;#39;s email and the different link URLs):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-12/user2s-links-index.png&quot; alt=&quot;Second user&amp;#39;s link index view&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s build the link redirection feature.&lt;/p&gt;
&lt;h2&gt;Redirecting Links and Incrementing Link Views in Phoenix&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s begin by adding a new controller to handle the redirect. This controller will have one &lt;code&gt;show&lt;/code&gt; action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot_web/controllers/redirect_controller.ex

defmodule UrlbotWeb.RedirectController do
  use UrlbotWeb, :controller

  alias Urlbot.Links

  def show(conn, %{&amp;quot;id&amp;quot; =&amp;gt; id}) do
    short_url = Links.get_short_url_link!(id)
    Links.increment_visits(short_url)
    redirect(conn, external: short_url.url)
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to modify the &lt;code&gt;Link&lt;/code&gt; context with a custom &lt;code&gt;get&lt;/code&gt; function that does not reference the current user:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/links.ex

defmodule Urlbot.Links do
  ...

  def get_short_url_link!(id) do
    Repo.get!(Link, id: id)
  end

  ...

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, modify the router accordingly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot_web/router.ex

defmodule UrlbotWeb.Router do
  use UrlbotWeb, :router
  use Pow.Phoenix.Router

  ...

  scope &amp;quot;/&amp;quot;, UrlbotWeb do
    pipe_through :browser

    get &amp;quot;/&amp;quot;, PageController, :home
    get &amp;quot;/links/:id&amp;quot;, RedirectController, :show # Add this line
  end

  ...

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, to handle the link view visits, we&amp;#39;ll add a custom function to the &lt;code&gt;Link&lt;/code&gt; context:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/links.ex

defmodule Urlbot.Links do
  ...

  def increment_visits(%Link{} = link) do
    from(s in Link, where: s.id == ^link.hash, update: [inc: [visits: 1]])
    |&amp;gt; Repo.update_all([])
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s it! Now, when we visit a link like &lt;code&gt;http://localhost:4000/links/rMbzTz3o&lt;/code&gt;, this should redirect to the original long URL and increment the link&amp;#39;s view counter.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;This two-part series has taken you on a journey to build a multi-tenant Elixir app using the Phoenix web framework. You&amp;#39;ve learned how to implement a simple tenant separation system using foreign keys and related models within a shared database and shared schema.&lt;/p&gt;
&lt;p&gt;Although we&amp;#39;ve tried to be as exhaustive as possible, we couldn&amp;#39;t possibly capture the whole app-building process, including testing, deployment options, or even the use of the amazing LiveView.&lt;/p&gt;
&lt;p&gt;All the same, we hope this tutorial provides a foundation for you to build your very own Elixir app that helps solve serious problems for your users.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Setting Up a Multi-tenant Phoenix App for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/11/21/setting-up-a-multi-tenant-phoenix-app-for-elixir.html"/>
    <id>https://blog.appsignal.com/2023/11/21/setting-up-a-multi-tenant-phoenix-app-for-elixir.html</id>
    <published>2023-11-21T00:00:00+00:00</published>
    <updated>2023-11-21T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first of a two-part series, we&#039;ll set up a multi-tenant Phoenix application.</summary>
    <content type="html">&lt;p&gt;Apps built with Elixir can support massive scalability, real-time interactivity, great fault tolerance, and the language&amp;#39;s syntax is actually a joy to use. Elixir is a natural fit for applications such as chat apps, data dashboard apps, and anything needed to support a large userbase.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll use Elixir — specifically, the web framework Phoenix — to build a multi-tenant link shortening app.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s Needed for Our Phoenix Project Built with Elixir&lt;/h2&gt;
&lt;p&gt;With the growing popularity of social media, there&amp;#39;s been an increase in the use of URL shortening services. As a budding entrepreneur, you believe there&amp;#39;s a market for yet another URL shortening service. And since such an app lives in between a generated short URL and the long version, it&amp;#39;s necessary that the app be fast and scalable.&lt;/p&gt;
&lt;p&gt;These features and more are already built into Phoenix, which makes it a great choice for this project, enabling you to stand out in the market.&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;After this tutorial, you will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Understand the internal workings of an Elixir/Phoenix app (for example, how to create and use a custom Ecto type, how to handle authentication, and more).&lt;/li&gt;
&lt;li&gt;Understand the concept of multi-tenancy, including the different strategies available.&lt;/li&gt;
&lt;li&gt;Build a multi-tenant link shortening Elixir/Phoenix app that can be extended into something more advanced with real-world use.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To follow along with the tutorial, let&amp;#39;s set up a few things.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Elixir installed on your development machine. If you don&amp;#39;t have it installed, follow &lt;a href=&quot;https://elixir-lang.org/install.html&quot;&gt;this guide&lt;/a&gt;. For this tutorial, we&amp;#39;re using Elixir version 1.14.0.&lt;/li&gt;
&lt;li&gt;Since we&amp;#39;ll be using Phoenix for the web app build, you&amp;#39;ll also need to &lt;a href=&quot;https://hexdocs.pm/phoenix/index.html&quot;&gt;have it installed&lt;/a&gt; on your local development machine. We&amp;#39;re using Phoenix version 1.7.2 in this tutorial.&lt;/li&gt;
&lt;li&gt;PostgreSQL - Ensure you have PostgreSQL installed, as it&amp;#39;s the default database used by Elixir/Phoenix apps.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that in place, let&amp;#39;s see what kind of app we&amp;#39;ll be building next.&lt;/p&gt;
&lt;h2&gt;An Overview of the Phoenix App We&amp;#39;ll Build&lt;/h2&gt;
&lt;p&gt;The app that we&amp;#39;ll build is a simple multi-tenant URL shortening app with the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User authentication&lt;/strong&gt; - users can register and log in to the application.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-tenant separation&lt;/strong&gt; - users can create shortened links within their own separate accounts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;URL shortening&lt;/strong&gt; - users can input normal links and generate shortened versions that redirect back to the original link when clicked.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;View metrics&lt;/strong&gt; - users can see how many times a link was clicked.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Implementing these features should add to your experience in working with Elixir and provide a good foundation to build even more complex Elixir apps.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s understand what multi-tenancy is and how it works.&lt;/p&gt;
&lt;h2&gt;An Overview of Multi-tenancy&lt;/h2&gt;
&lt;p&gt;At the most basic level, a multi-tenant app is one where the same application and database serve several tenants, with each client&amp;#39;s data kept separate from that of other clients. There are thousands of real-world multi-tenant app examples, including AppSignal, Gmail, and others.&lt;/p&gt;
&lt;p&gt;In our app, a user will be able to register and create shortened links that are associated with their account. Other users will also be able to sign up and create shortened links associated to them, but users won&amp;#39;t be able to see other users&amp;#39; links. This is a simplified but very good example of multi-tenancy in action.&lt;/p&gt;
&lt;p&gt;In the next section, we&amp;#39;ll outline the different strategies a developer can use when building a multi-tenant app. It&amp;#39;s important to point out that these strategies aren&amp;#39;t exclusive to Elixir. Rather, think of them as universal building blocks for developing multi-tenant apps regardless of the programming language used.&lt;/p&gt;
&lt;h2&gt;Multi-tenancy Strategies&lt;/h2&gt;
&lt;p&gt;Several multi-tenancy strategies are available, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Separate databases&lt;/strong&gt; - Here, each tenant gets their own database for complete isolation of each client&amp;#39;s data. The beauty of this approach is that it&amp;#39;s very scalable and great for applications where data security and isolation is key: for example, patient medical records, financial records, and other similar use cases. As you can imagine, one of the biggest disadvantages with this approach is how complex and costly it is to build and maintain apps using this strategy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A shared database with separate schema&lt;/strong&gt; - In this strategy, each client gets a separate schema within a shared database. This approach allows for a scalable system that is not too complex to build and maintain. That said, having separate schemas for each client is not something you can easily use to handle massive scale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A shared database with shared schema&lt;/strong&gt; - Here, all tenants share a common database and schema. It is a great choice for low-to-medium traffic apps and offers a convenient way to get started with multi-tenancy. Many SaaS startups are often built using this strategy. The biggest disadvantage of this strategy is that it&amp;#39;s not built for scale or speed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hybrid strategy&lt;/strong&gt; - A not-so-common approach where you have both the shared database and shared schema for some groups of users (say, the ones that pay the least in a SaaS app), and a common database with a separate schema for premium customers. This approach offers some level of scaling but is very complex to build and maintain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Containerization&lt;/strong&gt; - Similar to the separate databases approach, here, each tenant is provided with a completely separate and isolated app container. The obvious advantages are speed and scalability, but this is complex to build and maintain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You now have a good overview of what strategy to use when you build your own Elixir app next time.&lt;/p&gt;
&lt;p&gt;For this app project, we&amp;#39;ll be using the &lt;em&gt;shared database with shared schema&lt;/em&gt; approach and an app stack described in the next section.&lt;/p&gt;
&lt;h2&gt;Our Elixir Application Stack&lt;/h2&gt;
&lt;p&gt;To build our app project, we will use the up-and-coming Elixir stack called &amp;quot;PETAL&amp;quot;, short for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;P - Phoenix&lt;/li&gt;
&lt;li&gt;E - Elixir&lt;/li&gt;
&lt;li&gt;T - Tailwind CSS&lt;/li&gt;
&lt;li&gt;A - Alpine JS&lt;/li&gt;
&lt;li&gt;L - &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html&quot;&gt;Liveview&lt;/a&gt; - LiveView is an Elixir library that you include as a dependency in a Phoenix app to handle interactivity and other real-time flows characteristic of single-page applications (SPAs).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since our goals are simple, employing the full PETAL framework in this case is overkill. Instead, we&amp;#39;ll use the simple stack you get when you generate a new Phoenix web application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Phoenix&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;HTML and Tailwind CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are now ready to jump into the build, but before we do, it&amp;#39;s necessary that we understand how link shortening actually works. This will form the basis for the steps we&amp;#39;ll take during the build.&lt;/p&gt;
&lt;h2&gt;How Link Shortening Works&lt;/h2&gt;
&lt;p&gt;Link shortening is actually very simple. The link shortening app lies between a long URL and a generated short URL. When a visitor hits a short URL, their request is received by the app and a quick database search is done to find the matching long URL. Once that long URL is found, the visitor is redirected to it, and the link visits counter updates.&lt;/p&gt;
&lt;p&gt;Obviously, this is a very simplified outline, but it will suffice for now. Next, let&amp;#39;s start off our build.&lt;/p&gt;
&lt;h2&gt;Generating a New Phoenix Application&lt;/h2&gt;
&lt;p&gt;Begin by generating a new Phoenix application using the following &lt;code&gt;mix&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix phx.new urlbot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then open your project directory in a text editor and edit the &lt;code&gt;dev.exs&lt;/code&gt; file with your development environment&amp;#39;s database settings:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/dev.exs

import Config

config :shorten_my_links_app, ShortenMyLinksApp.Repo,
  username: &amp;quot;DATABASE USERNAME&amp;quot;, # Edit this line
  password: &amp;quot;DATABASE PASSWORD&amp;quot;, # Edit this line
  hostname: &amp;quot;localhost&amp;quot;,
  database: &amp;quot;DATABASE NAME&amp;quot;, # Edit this line
  stacktrace: true,
  show_sensitive_data_on_connection_error: true,
  pool_size: 10

  # ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create the database for the application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix ecto.create
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that is done, run &lt;code&gt;mix phx.server&lt;/code&gt; in the terminal to compile the application and spin up an instance of the compiled app on &lt;code&gt;localhost:4000&lt;/code&gt;, where you can see the default Phoenix home page:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-11/default-phoenix-app-homepage.png&quot; alt=&quot;Default Phoenix app homepage&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Next up, let&amp;#39;s set up the multi-tenant structure and user authentication.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Setting Up Multi-tenancy for Elixir&lt;/h2&gt;
&lt;p&gt;The tenant structure needs to be implemented as early as possible into a project build, since doing it later can result in all sorts of challenges. To put the &lt;em&gt;shared database with shared schema&lt;/em&gt; multi-tenant strategy that we chose into actuality, we&amp;#39;ll make use of foreign keys and related models.&lt;/p&gt;
&lt;p&gt;Specifically, we&amp;#39;ll have two main models: &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Account&lt;/code&gt; (this can also be called &lt;code&gt;Organization&lt;/code&gt;, &lt;code&gt;Team&lt;/code&gt;, or even &lt;code&gt;Company&lt;/code&gt;); a &lt;code&gt;User&lt;/code&gt; belongs to the &lt;code&gt;Account&lt;/code&gt; model.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll also have a third &lt;code&gt;Link&lt;/code&gt; model which will belong to the &lt;code&gt;Account&lt;/code&gt; model. This way, the &lt;code&gt;User&lt;/code&gt; model can be used exclusively for authentication purposes, while resource ownership will be handled by &lt;code&gt;Account&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This structure is represented in the diagram below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-11/multi-tenant-account-structure.png&quot; alt=&quot;Multi-tenant account structure&quot;/&gt;&lt;/p&gt;
&lt;p&gt;With this structure in place, all resources created, updated, or deleted in the app can be scoped to a specific &lt;code&gt;Account&lt;/code&gt; and &lt;code&gt;User&lt;/code&gt;. And just like that, we can achieve our goal of having separate tenant resources in a &lt;em&gt;shared database with shared schema&lt;/em&gt; setup.&lt;/p&gt;
&lt;p&gt;An additional benefit to using this structure is that you can easily expand it to invite other users to an account as &amp;quot;teammates&amp;quot; and assign them different roles. However, we won&amp;#39;t cover this feature in this tutorial.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s begin by generating the &lt;a href=&quot;https://hexdocs.pm/phoenix/contexts.html&quot;&gt;&lt;code&gt;Account&lt;/code&gt; context&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Generating an &lt;code&gt;Account&lt;/code&gt; Context&lt;/h2&gt;
&lt;p&gt;Generate the &lt;code&gt;Account&lt;/code&gt; context, schema, and migration file with the command below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix phx.gen.context Accounts Account accounts name:string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run the migration with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix ecto.migrate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let&amp;#39;s move on to the &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Building a &lt;code&gt;User&lt;/code&gt; Context and Authentication with Elixir&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;User&lt;/code&gt; context will be used for authentication purposes. Instead of generating the &lt;code&gt;User&lt;/code&gt; context and trying to integrate it into an authentication flow from scratch, Elixir gives us several libraries we can use, including &lt;a href=&quot;https://hexdocs.pm/phx_gen_auth/overview.html&quot;&gt;&lt;code&gt;phx.gen.auth&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/smpallen99/coherence&quot;&gt;Coherence&lt;/a&gt;, and &lt;a href=&quot;https://github.com/pow-auth/pow&quot;&gt;Pow&lt;/a&gt;, a modular and extendable authentication library for Phoenix apps.&lt;/p&gt;
&lt;p&gt;We first add Pow to the project&amp;#39;s dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs

defp deps do
  [
    # ...
    {:pow, &amp;quot;~&amp;gt; 1.0.30&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And fetch it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then finish by installing it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix pow.install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, we get a &lt;code&gt;User&lt;/code&gt; context, schema, and migration file. User authentication routes are also appended to the router.&lt;/p&gt;
&lt;p&gt;At this point, we could run the migration, but there are a couple of changes we should make to our generated user files first to ensure they are properly related.&lt;/p&gt;
&lt;h2&gt;Adding the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Account&lt;/code&gt; Relationship&lt;/h2&gt;
&lt;p&gt;Begin by adding a &lt;code&gt;belongs_to&lt;/code&gt; association to &lt;code&gt;User&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shorten_my_links_app/users/user.ex

defmodule Urlbot.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema

  schema &amp;quot;users&amp;quot; do
    pow_user_fields()

    belongs_to :account, Urlbot.Accounts.Account # Add this line

    timestamps()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s also modify &lt;code&gt;Account&lt;/code&gt; to include the &lt;code&gt;has_many&lt;/code&gt; relationship:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/accounts/account.ex

defmodule Urlbot.Accounts.Account do
  use Ecto.Schema
  import Ecto.Changeset

  schema &amp;quot;accounts&amp;quot; do
    field :name, :string

    has_many :users, Urlbot.Users.User # Add this line

    timestamps()
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let&amp;#39;s modify the &lt;code&gt;users&lt;/code&gt; migration to add the &lt;code&gt;account_id&lt;/code&gt; field as a foreign key. We also need to indicate that a user will be deleted whenever their related account is deleted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# priv/repo/migrations/XXXXXXXXXX_create_users.exs

defmodule Urlbot.Repo.Migrations.CreateUsers do
  use Ecto.Migration

  def change do
    create table(:users) do
      add :email, :string, null: false
      add :password_hash, :string

      # Add this line
      add :account_id, references(:accounts, on_delete: :delete_all), null: false

      timestamps()
    end

    create index(:users, [:account_id]) # Add this line
    create unique_index(:users, [:email])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, it&amp;#39;s nice to have an &lt;code&gt;Account&lt;/code&gt; automatically created the first time a user registers on the app.&lt;/p&gt;
&lt;h2&gt;Creating an &lt;code&gt;Account&lt;/code&gt; on User Registration&lt;/h2&gt;
&lt;p&gt;We need a way to capture the one attribute of the &lt;code&gt;Acccount&lt;/code&gt; model (the &lt;code&gt;account_name&lt;/code&gt; in the user registration form) and pass this attribute to a modified user creation process which will create a related &lt;code&gt;Account&lt;/code&gt; for us.&lt;/p&gt;
&lt;p&gt;That sounds like a lot, but let&amp;#39;s go step-by-step.&lt;/p&gt;
&lt;p&gt;First, add the &lt;code&gt;account_name&lt;/code&gt; attribute to the user registration form. Since we are working with Pow which comes with pre-built view templates, we need to generate the templates by running the command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix pow.phoenix.gen.templates
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate Pow&amp;#39;s view templates, but we are only interested in the user registration view for now. Edit it by adding the &lt;code&gt;account_name&lt;/code&gt; field:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot_web/controllers/pow/registration_html/new.html.heex

&amp;lt;div class=&amp;quot;mx-auto max-w-sm&amp;quot;&amp;gt;
  ...

  &amp;lt;.simple_form :let={f} for={@changeset} as={:user} action={@action} phx-update=&amp;quot;ignore&amp;quot;&amp;gt;
    ...

    &amp;lt;!-- Add this line --&amp;gt;
    &amp;lt;.input field={f[:account_name]} type=&amp;quot;text&amp;quot; label=&amp;quot;Account name&amp;quot; /&amp;gt;

    ...
  &amp;lt;/.simple_form&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the way, instead of adding the &lt;code&gt;account_name&lt;/code&gt; like this, we can use a nested form for working with &lt;code&gt;Account&lt;/code&gt; from &lt;code&gt;User&lt;/code&gt; (but this method should work just as well).&lt;/p&gt;
&lt;p&gt;Next, we want to add &lt;code&gt;account_name&lt;/code&gt; as a virtual attribute in the &lt;code&gt;User&lt;/code&gt; schema. The reason it&amp;#39;s a virtual attribute is simply because it&amp;#39;s not an attribute that is built into the &lt;code&gt;User&lt;/code&gt; schema, but we still need to use it in there. You can &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Schema.html&quot;&gt;read more on virtual attributes&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/urlbot/users/user.ex

defmodule Urlbot.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema

  schema &amp;quot;users&amp;quot; do
    pow_user_fields()

    # Add this line
    field :account_name, :string, virtual: true

    belongs_to :account, Urlbot.Accounts.Account

    timestamps()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, you can run &lt;code&gt;mix ecto.migrate&lt;/code&gt; to create the user table.&lt;/p&gt;
&lt;p&gt;Next, we want to make sure that the virtual attribute we&amp;#39;ve just added is passed on to the &lt;code&gt;User&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html&quot;&gt;changeset&lt;/a&gt;, which we&amp;#39;ll add since it&amp;#39;s not included by default when we run the Pow generator.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll also add a custom private function to create an account at the same time a user is created:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/shorten_my_links_app/users/user.ex

defmodule Urlbot.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema

  # Add this line since we&amp;#39;ll be using Ecto&amp;#39;s changeset in this schema
  import Ecto.Changeset

  # Add this line to reference Account since it&amp;#39;s used in the private function
  alias Urlbot.Accounts

  ...

  # Also add this block of code to add a changeset
  def changeset(user, attrs) do
    user
    |&amp;gt; pow_changeset(attrs)
    |&amp;gt; cast(attrs, [:account_name])
    |&amp;gt; validate_required([:account_name])
    |&amp;gt; create_user_account(user)
    |&amp;gt; assoc_constraint(:account)
  end

  # Add the custom private function
  defp create_user_account(%{valid?: true,  changes: %{account_name: account_name}} = changeset, %{account_id: nil} = _user) do
    with {:ok, account} &amp;lt;- Accounts.create_account(%{name: account_name}) do
      put_assoc(changeset, :account, account)
    else
      _ -&amp;gt; changeset
    end
  end

  defp create_user_account(changeset, _), do: changeset

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s break down what&amp;#39;s going on. First, we define a changeset block passing in a &lt;code&gt;user&lt;/code&gt; and the user attributes. Then we cast the virtual attribute we added, followed by a validation rule to make sure it&amp;#39;s present. We then call the private function &lt;code&gt;create_user_account&lt;/code&gt; (defined just below the changeset block) and finalize with an &lt;code&gt;assoc_constraint&lt;/code&gt; which checks that the associated field, &lt;code&gt;account_id&lt;/code&gt;, exists.&lt;/p&gt;
&lt;p&gt;With all that done, whenever a new user registers, a connected account will be automatically created. Any link resources created by the logged-in user will always be scoped to them. For example, an index view under &lt;em&gt;/links&lt;/em&gt; will only display links created by the user, and not list other users&amp;#39; links, even if they are available. This resource separation at the account or user level is the foundation of a multi-tenant structure.&lt;/p&gt;
&lt;h2&gt;Up Next: Adding &lt;code&gt;Link&lt;/code&gt; Resources and Custom Ecto Types&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve explored how multi-tenancy works and discussed a few multi-tenancy strategies. We created a Phoenix app and set up multi-tenancy. Finally, we added accounts, users and authentication, and associated users and accounts.&lt;/p&gt;
&lt;p&gt;In the next and final part of this series, we&amp;#39;ll look at:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generating the link resource&lt;/li&gt;
&lt;li&gt;Using Ecto custom types&lt;/li&gt;
&lt;li&gt;Generating a &lt;code&gt;current_account&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Assigning a &lt;code&gt;current_account&lt;/code&gt; to links&lt;/li&gt;
&lt;li&gt;Redirecting links and updating the &lt;code&gt;views&lt;/code&gt; counter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Validating Data in Elixir: Using Ecto and NimbleOptions</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/11/07/validating-data-in-elixir-using-ecto-and-nimbleoptions.html"/>
    <id>https://blog.appsignal.com/2023/11/07/validating-data-in-elixir-using-ecto-and-nimbleoptions.html</id>
    <published>2023-11-07T00:00:00+00:00</published>
    <updated>2023-11-07T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of our series, we&#039;ll explore how to avoid bad data using Ecto and NimbleOptions.</summary>
    <content type="html">&lt;p&gt;In the previous part of this series about validating data at the boundary of an Elixir application, we covered a few general programming tactics to try and reject invalid and unexpected data in our software.&lt;/p&gt;
&lt;p&gt;Continuing with that subject, we&amp;#39;ll now explore how two libraries, namely Ecto and NimbleOptions, can further assist us.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Using Ecto&lt;/h2&gt;
&lt;p&gt;As we&amp;#39;ve seen previously, Elixir provides many native techniques to help us guarantee data quality in our systems.&lt;/p&gt;
&lt;p&gt;But it&amp;#39;s also possible to leverage Ecto to cast, validate, and prune data even if there&amp;#39;s no database interaction.&lt;/p&gt;
&lt;h3&gt;Schemaless Changesets in Ecto&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#module-schemaless-changesets&quot;&gt;Schemaless changesets&lt;/a&gt; (basically Ecto changesets that aren&amp;#39;t tied to a database table) are a convenient way to create data structures. They also prevent bad data from making its way into structs (this can happen when bad data makes it past constructors or is added directly to a struct).&lt;/p&gt;
&lt;p&gt;This approach is typically helpful when dealing with untrusted input (e.g., from an API request or as part of a module&amp;#39;s public API). We can expose a function that will accept a plain map and, after proper vetting, will yield a struct. Other functions in the same module can then accept such a struct instance (rather than a map) to indicate that the data has been vetted and is safe to consume.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s what that approach can look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in the Account module

defstruct [:name, suspended: false]

def from_params(%{} = params) do
  data  = %{}
  types = %{name: :string, suspended: :boolean}

  changeset =
    {data, types}
    |&amp;gt; Ecto.Changeset.cast(params, Map.keys(types))
    |&amp;gt; Ecto.Changeset.validate_required(...)
    |&amp;gt; Ecto.Changeset.validate_length(...)

  case apply_action(changeset, :insert) do
    {:ok, data} -&amp;gt; {:ok, struct(__MODULE__, data)}
    {:error, _} = error -&amp;gt; error
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we&amp;#39;re applying an &lt;code&gt;:insert&lt;/code&gt; &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#module-changeset-actions&quot;&gt;action&lt;/a&gt;, so we could even use our function&amp;#39;s error to display directly in a Phoenix form: those require an &lt;code&gt;:insert&lt;/code&gt; or &lt;code&gt;:update&lt;/code&gt; action to render possible errors with the form&amp;#39;s data.&lt;/p&gt;
&lt;h3&gt;Applying This To Phoenix Forms&lt;/h3&gt;
&lt;p&gt;Indeed, &lt;a href=&quot;https://hexdocs.pm/phoenix_html/Phoenix.HTML.Form.html#module-a-note-on-errors&quot;&gt;Phoenix forms inspect the action&lt;/a&gt; to determine whether error hints should be displayed: if no action is set, no errors will be rendered in the form. This is useful if an empty changeset is being used to render a Phoenix form: the changeset is invalid, but we don&amp;#39;t want to berate the user with errors when they haven&amp;#39;t (yet) made any actual errors. But this also means that if you want the validation errors resulting from &lt;code&gt;from_params&lt;/code&gt; to show up in a Phoenix form, you need to set the &lt;code&gt;:action&lt;/code&gt; value yourself, which is what we&amp;#39;re accomplishing with our call to &lt;code&gt;apply_action&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course, if you don&amp;#39;t plan on using this with a Phoenix-rendered form, it won&amp;#39;t be needed and can be safely skipped.&lt;/p&gt;
&lt;p&gt;Creating a new validated account is now a simple matter of &lt;code&gt;Account.from_params(%{name: &amp;quot;ACME&amp;quot;, suspended: false})&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And since the &lt;code&gt;types&lt;/code&gt; are dynamic, they could also be passed in as arguments if your domain requires it.&lt;/p&gt;
&lt;h3&gt;Embedded Schemas in Ecto&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s say you already have an &lt;code&gt;Account&lt;/code&gt; struct that isn&amp;#39;t persisted to a database but still want to use Ecto to validate the data. In that case, you can transition to using an &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Schema.html#embedded_schema/1&quot;&gt;embedded schema&lt;/a&gt; rather than a basic struct. The trade-off between a schemaless changeset and an embedded schema is that the latter provides a bit more convenience at the expense of flexibility.&lt;/p&gt;
&lt;p&gt;Namely, embedded schemas require you to have a struct within which to define the schema. Schemaless changesets don&amp;#39;t have that requirement since, as their name implies, they don&amp;#39;t need a schema definition.&lt;/p&gt;
&lt;p&gt;Also, the datatypes for attributes can be dynamic in the schemaless changeset case (and provided as an argument to a function call, for example). In contrast, embedded schema types cannot vary from their defined value. Here&amp;#39;s the above example rewritten to use an embedded schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in the Account module

@primary_key false
embedded_schema do
  field :name, :string
  field :suspended, :boolean
end

def from_params(%{} = params) do
  changeset =
    %__MODULE__{}
    |&amp;gt; Ecto.Changeset.cast(params, [:name, :suspended])
    |&amp;gt; Ecto.Changeset.validate_required(...)
    |&amp;gt; Ecto.Changeset.validate_length(...)

  case apply_action(changeset, :insert) do
    {:ok, data} -&amp;gt; {:ok, struct(__MODULE__, data)}
    {:error, _} = error -&amp;gt; error
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#39;d like to dig deeper into how Ecto can &lt;em&gt;also&lt;/em&gt; help you with your non-persisted data, I highly recommend reading Ecto&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/ecto/data-mapping-and-validation.html&quot;&gt;Data mapping and validation guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Validating Options&lt;/h2&gt;
&lt;p&gt;There are many circumstances where data is passed in as keyword lists (e.g., options given to OTP modules such as GenServers). These values need to be validated for conformity, but we also want that validation to be easy to understand and communicate. Enter NimbleOptions!&lt;/p&gt;
&lt;h3&gt;The NimbleOptions Library for Elixir&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/nimble_options/NimbleOptions.html&quot;&gt;NimbleOptions&lt;/a&gt; is a great tool for validating options, as it is a lightweight library that verifies keyword lists and returns errors on invalid data. Let&amp;#39;s see how it can be used!&lt;/p&gt;
&lt;p&gt;Say we want to email suspended &lt;code&gt;Account&lt;/code&gt; records. The email template to use will be different if we email a corporate or personal account. Additionally, you want to specify which values to pass into the template.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll want to adapt the signature: corporate accounts, for example, should have an account manager&amp;#39;s name attached, while private accounts can simply have a generic signature. We&amp;#39;ll also specify which URL to include as the call to action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def email(%Account{} = account, opts) when is_list(opts) do
  template = Keyword.fetch!(opts, :template)
  values = Keyword.get(opts, :values, [])
  account_url = Keyword.get(values, :landing_url)
  signature = Keyword.get(values, :signature, &amp;quot;Yours truly,\nACME.com&amp;quot;)

  # email generation and sending goes here

  :ok
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a great start: we&amp;#39;re enforcing the &lt;code&gt;:template&lt;/code&gt; to be provided and the program will crash if the template isn&amp;#39;t given. This keeps out bad data, but isn&amp;#39;t a great experience for callers: if they make a mistake (even as simple as a typo on the template name!) everything is going to crash instead of just generating an error they can handle.&lt;/p&gt;
&lt;p&gt;We could, of course, do something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def email(%Account{} = account, opts) when is_list(opts) do
  with template when template in ~w(personal corporate)a &amp;lt;- Keyword.get(opts, :template) do
    values = Keyword.get(opts, :values, [])
    landing_url = %URI{} = Keyword.get(values, :landing_url, URI.parse(&amp;quot;https://www.example.com/sign_in&amp;quot;))
    signature = Keyword.get(values, :signature, &amp;quot;Yours truly,\nACME.com&amp;quot;)

    # email generation and sending goes here

    :ok
  else
    nil -&amp;gt; {:error, :missing_tempate}
    other when is_atom(other) -&amp;gt; {:error, :invalid_template_value}
    _ -&amp;gt;  {:error, :invalid_template_type}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But that doesn&amp;#39;t scale very well once the number of options grows: it gets pretty difficult to see what options are permitted, what their expected type is, and so on. Not to mention, this is going to get repetitive really fast.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Bringing In NimbleOptions&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s try out NimbleOptions. We need to specify a schema that the options are expected to conform to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@email_opts_schema [
  template: [
    required: true,
    type: {:in, ~w(personal corporate)a}
  ],
  values: [
    type: :keyword_list,
    default: [],
    keys: [
      landing_url: [
        type: {:struct, URI},
        default: URI.parse(&amp;quot;https://www.example.com/sign_in&amp;quot;)
      ],
      signature: [
        type: :string,
        default: &amp;quot;Yours truly,\nACME.com&amp;quot;
      ]
    ]
  ]
]

def email(%Account{} = account, opts) when is_list(opts) do
  with {:ok, validated_options} &amp;lt;- NimbleOptions.validate(opts, @email_opts_schema) do
    template = Keyword.fetch!(validated_options, :template)
    landing_url = validated_options[:values][:landing_url]
    signature = validated_options[:values][:landing_url]

    # email generation and sending goes here

    {:ok, validated_options}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do note we&amp;#39;ve specified &lt;code&gt;default: []&lt;/code&gt; in the &lt;code&gt;values&lt;/code&gt; configuration: that way, an empty list will be used as the default, enabling the cascading of default child values such as &lt;code&gt;landing_url&lt;/code&gt; to be filled in. Without it, a default &lt;code&gt;landing_url&lt;/code&gt; won&amp;#39;t be filled in if a &lt;code&gt;values&lt;/code&gt; keyword isn&amp;#39;t present at all.&lt;/p&gt;
&lt;p&gt;Here it is in action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; email(an_account, template: :personal)

{:ok,
 [
   values: [
     signature: &amp;quot;Yours truly,\nACME.com&amp;quot;,
     landing_url: %URI{
       authority: &amp;quot;www.example.com&amp;quot;,
       fragment: nil,
       host: &amp;quot;www.example.com&amp;quot;,
       path: &amp;quot;/sign_in&amp;quot;,
       port: 443,
       query: nil,
       scheme: &amp;quot;https&amp;quot;,
       userinfo: nil
     }
   ],
   template: :personal
 ]}

iex&amp;gt; email(an_account, template: :personal, values: [signature: &amp;quot;With love,\nBob&amp;quot;])

{:ok,
 [
   template: :personal,
   values: [
     landing_url: %URI{
       authority: &amp;quot;www.example.com&amp;quot;,
       fragment: nil,
       host: &amp;quot;www.example.com&amp;quot;,
       path: &amp;quot;/sign_in&amp;quot;,
       port: 443,
       query: nil,
       scheme: &amp;quot;https&amp;quot;,
       userinfo: nil
     },
     signature: &amp;quot;With love,\nBob&amp;quot;
   ]
 ]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see, default values are being filled in when required, and they won&amp;#39;t overwrite any provided values.&lt;/p&gt;
&lt;p&gt;Validation also works out of the box:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; email(an_account, template: :boom)

{:error,
 %NimbleOptions.ValidationError{
   key: :template,
   keys_path: [],
   message: &amp;quot;invalid value for :template option: expected one of [:personal, :corporate], got: :boom&amp;quot;,
   value: :boom
 }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will also verify that we&amp;#39;re not passing in unexpected option keys, such as typos:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; email(an_account, template: :personal, values: [singature: &amp;quot;With love,\nBob&amp;quot;])

{:error,
 %NimbleOptions.ValidationError{
   key: [:singature],
   keys_path: [:values],
   message: &amp;quot;unknown options [:singature], valid options are: [:landing_url, :signature]&amp;quot;,
   value: nil
 }}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Allowing Strings for &lt;code&gt;landing_page&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;While having the &lt;code&gt;landing_page&lt;/code&gt; as a URI ensures it at least looks right, having to provide it as a string is a bit of a pain. It would be nice to provide the option as a string, but here&amp;#39;s how that currently behaves:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; email(an_account, template: :personal, values: [landing_url: &amp;quot;https://my.app&amp;quot;])

{:error,
 %NimbleOptions.ValidationError{
   key: :landing_url,
   keys_path: [:values],
   message: &amp;quot;invalid value for :landing_url option: expected URI, got: \&amp;quot;https://my.app\&amp;quot;&amp;quot;,
   value: &amp;quot;https://my.app&amp;quot;
 }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Luckily, there&amp;#39;s an easy fix — we just have to tweak the type definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@email_opts_schema [
  template: [
    required: true,
    type: {:in, ~w(personal corporate)a}
  ],
  values: [
    type: :keyword_list,
    default: [],
    keys: [
      landing_url: [
        # improved type to accept strings
        type: {:or, [{:struct, URI}, :string]},
        default: URI.parse(&amp;quot;https://www.example.com/sign_in&amp;quot;)
      ],
      signature: [
        type: :string,
        default: &amp;quot;Yours truly,\nACME.com&amp;quot;
      ]
    ]
  ]
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Strings are now accepted for the &lt;code&gt;landing_page&lt;/code&gt; value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; email(an_account, template: :personal, values: [landing_url: &amp;quot;https://my.app&amp;quot;])

{:ok,
 [
   template: :personal,
   values: [signature: &amp;quot;Yours truly,\nACME.com&amp;quot;, landing_url: &amp;quot;https://my.app&amp;quot;]
 ]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While a step in the right direction, there are now two minor issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our code has to handle both string and URI data types (or we need to manually convert one to another after validation).&lt;/li&gt;
&lt;li&gt;Leaving the value as a string doesn&amp;#39;t indicate anything. In particular, there&amp;#39;s no indication that the value is a valid URI &amp;quot;safe&amp;quot; to process.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Elixir&amp;#39;s NimbleOptions To the Rescue!&lt;/h3&gt;
&lt;p&gt;Once again, NimbleOptions comes to our rescue: we can use a &lt;a href=&quot;https://hexdocs.pm/nimble_options/NimbleOptions.html#module-types&quot;&gt;&lt;code&gt;:custom&lt;/code&gt; data type&lt;/a&gt; that specifies a parser function. In our case, that parser function can simply be &lt;code&gt;URI.new/1&lt;/code&gt;, as it already conforms to the expectation set by &lt;code&gt;:custom&lt;/code&gt; (namely, returning &lt;code&gt;{:ok, value}&lt;/code&gt; or &lt;code&gt;{:error, message}&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@email_opts_schema [
  template: [
    required: true,
    type: {:in, ~w(personal corporate)a}
  ],
  values: [
    type: :keyword_list,
    default: [],
    keys: [
      landing_url: [
        # also accept strings, but parse them in %URI{}
        type: {:or, [{:struct, URI}, {:custom, URI, :new, []}]},
        default: URI.parse(&amp;quot;https://www.example.com/sign_in&amp;quot;)
      ],
      signature: [
        type: :string,
        default: &amp;quot;Yours truly,\nACME.com&amp;quot;
      ]
    ]
  ]
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check it out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; email(an_account, template: :personal, values: [landing_url: &amp;quot;https://my.app&amp;quot;])

{:ok,
 [
   template: :personal,
   values: [
     signature: &amp;quot;Yours truly,\nACME.com&amp;quot;,
     landing_url: %URI{
       authority: nil,
       fragment: nil,
       host: &amp;quot;my.app&amp;quot;,
       path: nil,
       port: 443,
       query: nil,
       scheme: &amp;quot;https&amp;quot;,
       userinfo: nil
     }
   ]
 ]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ve now got the best of both worlds: convenient argument types and a standardized representation post-validation!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;I hope you&amp;#39;ve enjoyed these two blog posts covering how you can keep bad data out of your Elixir applications while also making your code more expressive.&lt;/p&gt;
&lt;p&gt;As we&amp;#39;ve seen, there are both &amp;quot;plain vanilla&amp;quot; Elixir techniques as well as support you can get from libraries like NimbleOptions to help us reject invalid data from being processed in our code.&lt;/p&gt;
&lt;p&gt;By introducing these approaches to our modules, we&amp;#39;ll provide more immediate feedback to callers and also make our programs more resilient when faced with unexpected data.&lt;/p&gt;
&lt;p&gt;Hopefully, you&amp;#39;ve now got a few more tools in your belt to try out. Enjoy!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How To Use Zig for Elixir NIFs</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/10/24/how-to-use-zig-for-elixir-nifs.html"/>
    <id>https://blog.appsignal.com/2023/10/24/how-to-use-zig-for-elixir-nifs.html</id>
    <published>2023-10-24T00:00:00+00:00</published>
    <updated>2023-10-24T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how to set up Zig for Elixir NIFs and integrate a NIF into an Elixir application.</summary>
    <content type="html">&lt;p&gt;Elixir excels at building scalable and maintainable applications. However, sometimes Elixir is not the best language to tackle specific tasks, and it can fall short in some areas, like direct system interaction.&lt;/p&gt;
&lt;p&gt;Fortunately, Elixir offers NIFs (Native Implemented Functions): a path for integrating with other languages to improve these gaps. NIFs in Elixir act as an interface to call functions written in native languages like C or Rust, enabling developers to optimize performance-critical sections of their code.&lt;/p&gt;
&lt;p&gt;NIFs can be written in many languages like Rust, Python, and Zig. For this tutorial, we will use Zig, due to its simplicity, speed, and safety.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;What We&amp;#39;ll Cover&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll cover the following topics in this tutorial:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting up Zig for Elixir NIF development.&lt;/li&gt;
&lt;li&gt;Understanding NIFs in Elixir.&lt;/li&gt;
&lt;li&gt;Writing a simple NIF in Zig.&lt;/li&gt;
&lt;li&gt;Integrating the NIF with an Elixir application.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What Is Zig?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ziglang.org/&quot;&gt;Zig&lt;/a&gt; is a general-purpose programming language designed for robustness, optimality, and maintainability.&lt;/p&gt;
&lt;p&gt;It is known to provide excellent debugging and error-handling capabilities, making it suitable for various applications (including systems programming, embedded systems, and performance-critical applications).&lt;/p&gt;
&lt;h2&gt;Setting up Zig for Elixir Development&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s now look at how we can set up Zig for Elixir NIF development.&lt;/p&gt;
&lt;h3&gt;Installing Zig&lt;/h3&gt;
&lt;p&gt;To get started with Zig, download the latest version of the Zig compiler from the &lt;a href=&quot;https://ziglang.org/download/&quot;&gt;official Zig website&lt;/a&gt;. Follow the installation instructions for your specific operating system.&lt;/p&gt;
&lt;h3&gt;Configuring Zig for Elixir NIF Development&lt;/h3&gt;
&lt;p&gt;To configure Zig for Elixir NIF development, you&amp;#39;ll need to include the necessary libraries and dependencies.&lt;/p&gt;
&lt;p&gt;Elixir NIFs rely on the Erlang NIF API provided by the &lt;code&gt;erl_nif.h&lt;/code&gt; header file. Ensure you have the Erlang development package installed, and include the appropriate path to &lt;code&gt;erl_nif.h&lt;/code&gt; in your build script or Zig build file.&lt;/p&gt;
&lt;p&gt;Just add the following line to your &lt;code&gt;src/main.zig&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zig&quot;&gt;const erl = @cImport({
    @cInclude(&amp;quot;erl_nif.h&amp;quot;);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importing this library will allow us to use the Erlang NIF API in our Zig code. It contains the native functions that allow our Zig code to interact with the Erlang VM. Later in this tutorial, we will see how to use this library to create our NIF.&lt;/p&gt;
&lt;h3&gt;Verifying the Setup&lt;/h3&gt;
&lt;p&gt;To verify that Zig is correctly set up for Elixir NIF development, we will create a simple &amp;quot;Hello, World!&amp;quot; project in Zig.&lt;/p&gt;
&lt;p&gt;Go ahead and run the following commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir hello-world
cd hello-world
zig init-exe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;zig&lt;/code&gt; has been installed correctly, you should see the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;info: Created build.zig
info: Created src/main.zig
info: Next, try `zig build --help` or `zig build run`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we&amp;#39;ll run &lt;code&gt;zig build run&lt;/code&gt; on our terminal to ensure we can compile and execute a Zig program. If successful, you should see the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;All your codebase are belong to us.
Run `zig build test` to run the tests.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we are able to compile and run Zig code, we can move forward.&lt;/p&gt;
&lt;h2&gt;Understanding NIFs in Elixir&lt;/h2&gt;
&lt;h3&gt;Why Use NIFs in Elixir?&lt;/h3&gt;
&lt;p&gt;NIFs can be called from Elixir code, providing a performance boost for computationally intensive tasks. While Elixir excels at concurrency and fault tolerance, there might be better choices for performance-sensitive tasks.&lt;/p&gt;
&lt;p&gt;By writing NIFs in a lower-level language like Zig, you can leverage the language&amp;#39;s speed and efficiency without sacrificing Elixir&amp;#39;s maintainability and concurrency features.&lt;/p&gt;
&lt;h3&gt;Advantages of Using Zig for NIF Development&lt;/h3&gt;
&lt;p&gt;Zig offers several advantages for NIF development:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt;: Zig compiles to efficient native code, providing significant performance improvements over interpreted languages like Elixir.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safety&lt;/strong&gt;: Zig has strong static typing, compile-time checks, and a focus on error handling, reducing the likelihood of runtime errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity&lt;/strong&gt;: Zig&amp;#39;s straightforward syntax and semantics make it easy to learn and use, especially for developers familiar with C or C++. Zig&amp;#39;s standard library is also very comprehensive, providing a wide range of functionality for common tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Writing our First NIF&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s start by setting up our Elixir project. Run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix new example_nif
cd example_nif
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;This will create a basic Elixir project called &lt;code&gt;ExampleNif&lt;/code&gt;. Next, let&amp;#39;s initialize the Zig project inside our Elixir project with the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;zig init-lib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will initialize a library inside our project that will create the following files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build.zig&lt;/code&gt; - which contains the code for compiling and building our zig library.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/main.zig&lt;/code&gt; - this is the main code of our library and will contain the logic that we will implement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Writing a Simple NIF in Zig&lt;/h3&gt;
&lt;p&gt;Our first step when working with Zig is to update the &lt;code&gt;build.zig&lt;/code&gt; file with the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zig&quot;&gt;const std = @import(&amp;quot;std&amp;quot;);
const Pkg = std.build.Pkg;

pub fn build(b: *std.build.Builder) void {
    const mode = b.standardReleaseOptions();

    const nif_step = b.step(&amp;quot;example_lib&amp;quot;, &amp;quot;Compiles erlang library&amp;quot;);
    const example_lib = b.addSharedLibrary(&amp;quot;example_nif&amp;quot;, &amp;quot;./src/main.zig&amp;quot;, .unversioned);
    example_lib.setBuildMode(mode);
    example_lib.setOutputDir(&amp;quot;build&amp;quot;);
    example_lib.addIncludePath(&amp;quot;/usr/lib/erlang/usr/include/&amp;quot;);

    example_lib.install();
    example_lib.linkLibC();
    nif_step.dependOn(&amp;amp;example_lib.step);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will add the Erlang header path to the build environment and also link with the C library.&lt;/p&gt;
&lt;p&gt;Next, we will update the &lt;code&gt;src/main.zig&lt;/code&gt; code. For this example, we&amp;#39;ll create a simple NIF that takes two integers and returns their sum. This function will be written in Zig and called from Elixir code.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zig&quot;&gt;const std = @import(&amp;quot;std&amp;quot;);
const erl = @cImport({
    @cInclude(&amp;quot;erl_nif.h&amp;quot;);
});

export fn nif_add(
    env: ?*erl.ErlNifEnv,
    argc: c_int,
    argv: [*c]const erl.ERL_NIF_TERM,
) erl.ERL_NIF_TERM {
    var a: i32 = undefined;
    var b: i32 = undefined;

    if ((argc != 2))
    {
        return erl.enif_make_badarg(env);
    }

    _ = erl.enif_get_int(env, argv[0], &amp;amp;a);
    _ = erl.enif_get_int(env, argv[1], &amp;amp;b);

    const result = a + b;
    return erl.enif_make_int(env, result);
}

const func_count = 1;

var funcs = [func_count]erl.ErlNifFunc{
    erl.ErlNifFunc{
        .name = &amp;quot;nif_add&amp;quot;,
        .arity = 2,
        .fptr = nif_add,
        .flags = 0,
    },
};

var entry = erl.ErlNifEntry{
    .major = erl.ERL_NIF_MAJOR_VERSION,
    .minor = erl.ERL_NIF_MINOR_VERSION,
    .name = &amp;quot;Elixir.ExampleNif&amp;quot;,
    .num_of_funcs = func_count,
    .funcs = &amp;amp;funcs,
    .load = null,
    .reload = null,
    .upgrade = null,
    .unload = null,
    .vm_variant = &amp;quot;beam.vanilla&amp;quot;,
    .options = 1,
    .sizeof_ErlNifResourceTypeInit = @sizeOf(erl.ErlNifResourceTypeInit),
    .min_erts = &amp;quot;erts-10.4&amp;quot;,
};

export fn nif_init() *erl.ErlNifEntry {
    return &amp;amp;entry;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this code may look intimidating, it&amp;#39;s actually quite simple. Let&amp;#39;s break it down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We are first importing the &lt;code&gt;erl_nif.h&lt;/code&gt; header file, which contains the definitions for the Erlang NIF API and the std library.&lt;/li&gt;
&lt;li&gt;Next, we define our first and only library function, &lt;code&gt;nim_add&lt;/code&gt;, which takes three arguments:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;env&lt;/code&gt; is a pointer to an &lt;code&gt;ErlNifEnv&lt;/code&gt; struct, which contains the environment for the NIF. This struct is used to allocate memory, create Erlang terms, and more.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;argc&lt;/code&gt; is the number of arguments passed to the NIF.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;argv&lt;/code&gt; is an array of Erlang terms (the arguments passed to the NIF).&lt;/li&gt;
&lt;li&gt;The function code itself is a very simple and naive implementation that adds two integers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After we have defined all our functions, we define a constant &lt;code&gt;func_count&lt;/code&gt; (the number of functions in the NIF).&lt;/li&gt;
&lt;li&gt;We then define an array of &lt;code&gt;ErlNifFunc&lt;/code&gt; structs, containing the name, arity, and function pointer for each function in the NIF.&lt;/li&gt;
&lt;li&gt;Finally, we define an &lt;code&gt;ErlNifEntry&lt;/code&gt; struct, which contains the NIF&amp;#39;s version, name, and functions. This struct is used to register the NIF with the Erlang VM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is important to highlight that the &lt;code&gt;num_of_funcs&lt;/code&gt; field in the &lt;code&gt;ErlNifEntry&lt;/code&gt; struct must match the number of functions in the &lt;code&gt;funcs&lt;/code&gt; array. The &lt;code&gt;name&lt;/code&gt; field must also match the module name and function in the &lt;code&gt;NIF_MOD_FUNCS&lt;/code&gt; of the &lt;code&gt;build.zig&lt;/code&gt; file.&lt;/p&gt;
&lt;h3&gt;Compiling the Zig Code Into a NIF&lt;/h3&gt;
&lt;p&gt;To compile the Zig code into a NIF, use the zig build-lib command, specifying the appropriate target and output file. For example, on a Linux system:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;zig build example_lib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command will produce a shared library file: &lt;code&gt;libexample_nif.so&lt;/code&gt; in the &lt;code&gt;build/&lt;/code&gt; directory.&lt;/p&gt;
&lt;h3&gt;Integrating the NIF with Elixir&lt;/h3&gt;
&lt;p&gt;To use the NIF in Elixir, we need to follow several steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load the shared library containing the NIF.&lt;/li&gt;
&lt;li&gt;Define a fallback function to handle cases where the NIF is not loaded.&lt;/li&gt;
&lt;li&gt;Call the NIF function from our Elixir code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Loading the Shared Library&lt;/h4&gt;
&lt;p&gt;When using NIFs, Elixir needs to load the shared library containing the native code. To do this, we use the &lt;code&gt;:erlang.load_nif/2&lt;/code&gt; function, which takes two arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The relative path to the shared library (&lt;code&gt;.so&lt;/code&gt; on Linux, &lt;code&gt;.dll&lt;/code&gt; on Windows, or &lt;code&gt;.dylib&lt;/code&gt; on macOS).&lt;/li&gt;
&lt;li&gt;An optional integer value (usually 0) can be used for versioning purposes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our Elixir module, we&amp;#39;ll define a &lt;code&gt;load_nif/0&lt;/code&gt; private function that handles loading the shared library. We&amp;#39;ll also use the &lt;code&gt;@on_load&lt;/code&gt; module attribute to specify that &lt;code&gt;load_nif/0&lt;/code&gt; should be called when the module is loaded.&lt;/p&gt;
&lt;h4&gt;Defining a Fallback Function&lt;/h4&gt;
&lt;p&gt;It&amp;#39;s important to provide a fallback function that will be called if the NIF fails to load. This function should have the same name and arity as the NIF function and return an error tuple such as &lt;code&gt;{:error, reason}&lt;/code&gt; or call the &lt;code&gt;:erlang.nif_error/1&lt;/code&gt; BIF (Built-In Function) with an appropriate error reason.&lt;/p&gt;
&lt;p&gt;In our example, we define an &lt;code&gt;add/2&lt;/code&gt; fallback function that calls &lt;code&gt;:erlang.nif_error&lt;/code&gt;(&lt;code&gt;:nif_not_loaded&lt;/code&gt;).&lt;/p&gt;
&lt;h4&gt;Calling the NIF Function from Elixir Code&lt;/h4&gt;
&lt;p&gt;Once the shared library is loaded and the NIF function is linked to the Elixir module, you can call the NIF function just like any other Elixir function. In our example, we call &lt;code&gt;ExampleNif.add/2&lt;/code&gt; to perform the addition using the NIF we wrote in Zig.&lt;/p&gt;
&lt;p&gt;By following these steps, you can seamlessly integrate NIFs written in Zig into your Elixir applications, taking advantage of both the performance benefits of Zig and the maintainability and concurrency features of Elixir.&lt;/p&gt;
&lt;h3&gt;Writing Elixir Code to Use the NIF&lt;/h3&gt;
&lt;p&gt;Create a new Elixir module called &lt;code&gt;ExampleNif&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ExampleNif do
  @on_load :load_nif

  def load_nif do
    :erlang.load_nif(&amp;#39;./build/libexample_nif&amp;#39;, 0)
  end

  def nif_add(_a, _b), do: :erlang.nif_error(:nif_not_loaded)

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s review this. We:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create an Elixir module called &lt;code&gt;ExampleNif&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Specify that the &lt;code&gt;load_nif/0&lt;/code&gt; function should be called when the module is loaded.&lt;/li&gt;
&lt;li&gt;Define a private function, &lt;code&gt;load_nif/0&lt;/code&gt;, that loads the shared library containing the NIF.&lt;/li&gt;
&lt;li&gt;Define a fallback function (&lt;code&gt;nif_add/2&lt;/code&gt;) that will be called if the NIF fails to load.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;&lt;code&gt;:erlang.load_nif&lt;/code&gt; loads and links the Zig compiled library to the Elixir module; and it also loads this function before the definition of our &lt;code&gt;nif_add/2&lt;/code&gt; fallback function. This is why we need to define the fallback function &lt;code&gt;nif_add/2&lt;/code&gt; with the same arity and name as the NIF function.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Because of Elixir&amp;#39;s pattern-matching capabilities, the fallback function will handle calls to &lt;code&gt;nif_add/2&lt;/code&gt; if the NIF is not loaded, and if the NIF is loaded, the NIF function will handle the call as defined in &lt;code&gt;load_nif/0&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Verifying That the NIF Works&lt;/h3&gt;
&lt;p&gt;To verify that the NIF is working as expected, create a simple test program in Elixir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ExampleNifTest do
  use ExUnit.Case

  test &amp;quot;add/2 NIF&amp;quot; do
    assert ExampleNif.nif_add(1, 2) == 3
    assert ExampleNif.nif_add(-5, 10) == 5
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the test suite using mix test. If the tests pass, it indicates that the NIF is functioning correctly, and our addition is done through our Zig compiled library rather than on Elixir code directly.&lt;/p&gt;
&lt;h3&gt;Considerations&lt;/h3&gt;
&lt;p&gt;It is amazing that we can use code from another language through NIF. However, there are a few things you might want to be aware of, starting with the parameters we initially declared on our Zig library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-zig&quot;&gt;export fn nif_add(
    env: ?*erl.ErlNifEnv,
    argc: c_int,
    argv: [*c]const erl.ERL_NIF_TERM,
) erl.ERL_NIF_TERM {
    var a: i32 = undefined;
    var b: i32 = undefined;
...
    _ = erl.enif_get_int(env, argv[0], &amp;amp;a);
    _ = erl.enif_get_int(env, argv[1], &amp;amp;b);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are parsing the first two arguments and casting them into an integer. What happens if we pass a float value to this function? Try it out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;iex(3)&amp;gt; ExampleNif.nif_add(-100.0,-11)
-1431655777
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We get junk values, as there are no type checks or logic to handle float values in our Zig function. These can cause unexpected bugs and issues that developers need to be more vigilant to catch.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we set up Zig for Elixir NIF development, wrote a simple NIF in Zig, and integrated the NIF with an Elixir application.&lt;/p&gt;
&lt;p&gt;By leveraging the strengths of both Elixir and Zig, developers can create efficient, maintainable, and performant applications.&lt;/p&gt;
&lt;p&gt;That said, NIFs should be used with caution and deliberately. Ensure you add the necessary tests and failsafes.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Validate Data in a Phoenix Application for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/10/10/validate-data-in-a-phoenix-application-for-elixir.html"/>
    <id>https://blog.appsignal.com/2023/10/10/validate-data-in-a-phoenix-application-for-elixir.html</id>
    <published>2023-10-10T00:00:00+00:00</published>
    <updated>2023-10-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first of a two-part series, we&#039;ll explore how to avoid bad data and validate data at the boundary of a Phoenix application.</summary>
    <content type="html">&lt;p&gt;In this first part of a two-part series, we&amp;#39;ll explore how to avoid bad data and validate data at the boundary of a Phoenix application.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll use a few techniques to ensure that bad data doesn&amp;#39;t degrade our application.&lt;/p&gt;
&lt;p&gt;In part two, we&amp;#39;ll specifically focus on leveraging Ecto under the hood to cast data.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;Say No to Bad Data in Elixir&lt;/h2&gt;
&lt;p&gt;Bad data must be dealt with immediately, or it will spread throughout your system and degrade other data. Given how difficult and time-consuming it is to fix data issues, preventing bad data from entering your system is well worth the effort.&lt;/p&gt;
&lt;p&gt;Here is what the &lt;a href=&quot;https://hexdocs.pm/elixir/library-guidelines.html#avoid-working-with-invalid-data&quot;&gt;official Elixir documentation&lt;/a&gt; has to say on the matter:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[...] when you don&amp;#39;t validate the values at the boundary, the internals of your library are never quite sure which kind of values they are working with.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This advice does not only apply to libraries, but to any Elixir code. Every time you receive multiple options or work with external data, you should validate the data at the boundary and convert it to structured data. For example, if you provide a &lt;a href=&quot;https://hexdocs.pm/elixir/GenServer.html&quot;&gt;&lt;code&gt;GenServer&lt;/code&gt;&lt;/a&gt; that can be started with multiple options, you want to validate those options when the server starts and rely only on structured data throughout the process life cycle. Similarly, if a database or a socket gives you a map of strings, after you receive the data, you should validate it and potentially convert it to a struct or a map of atoms.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But what &lt;em&gt;is&lt;/em&gt; a boundary, and where does it live? The answer, dear reader, is mostly up to you. In a sense, boundaries exist wherever your functions accept unknown or unsafe data, to later be processed (once some assumptions about the data are made).&lt;/p&gt;
&lt;h2&gt;An Example of a Boundary in a Phoenix App&lt;/h2&gt;
&lt;p&gt;A typical example of a boundary in a Phoenix app is the boundary between the web layer and the business logic: parameters come in as JSON values and are parsed into maps with string keys. But a client is free to send any sort of data within the JSON payload: there could be incorrect keys, invalid values, extra key values, and so on.&lt;/p&gt;
&lt;p&gt;Since you don&amp;#39;t want to deal with this unwieldy data in every location within your app, the recommendation is to process this untrusted data in a single location and convert it into a well-known shape with validated content.&lt;/p&gt;
&lt;p&gt;This is typically done in a &lt;a href=&quot;https://hexdocs.pm/phoenix/contexts.html&quot;&gt;Phoenix Context&lt;/a&gt;, where &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#cast/4&quot;&gt;Ecto&lt;/a&gt; is leveraged under the hood to cast data (we&amp;#39;ll explore this in our next post). Once this conversion has taken place, your domain logic can trust the content of the request payload without performing the same verification again.&lt;/p&gt;
&lt;p&gt;More generally speaking, boundaries will typically crop up anywhere in your software where you accept some data of unknown quality and process it internally (typically over several iterations). Examples include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GenServers - where data is sent and processed into state changes.&lt;/li&gt;
&lt;li&gt;Web requests - which make their way to domain logic and database tables.&lt;/li&gt;
&lt;li&gt;Console input - which needs to be processed into arguments provided to a CLI application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, boundaries can also show up when data has different meaning in different contexts (often called bounded contexts): a Customer might, for example, have a billing address, and a User might have a username, but both would refer to the same person in the world. In effect, boundaries are everywhere, which makes these techniques very handy when they&amp;#39;re skillfully deployed.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s now check out a few techniques to prevent bad data from degrading our application.&lt;/p&gt;
&lt;h2&gt;Pattern Matching and Guards in Elixir&lt;/h2&gt;
&lt;p&gt;At the very local level, we can leverage pattern matching and guards to ensure we&amp;#39;re always working with the data we expect.&lt;/p&gt;
&lt;p&gt;This type of defensive code is beneficial anywhere you add it, be it within domain code (such as a Phoenix Context), the interface layer (in a Phoenix Controller, for example), or even deep within a free-standing function in a script.&lt;/p&gt;
&lt;h3&gt;Case Clauses&lt;/h3&gt;
&lt;p&gt;Case clauses can be very helpful in ensuring we explicitly list the data we agree to handle, particularly if there&amp;#39;s no catch-all clause:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;case Account.setup(...) do
    {:ok, %Account{suspended: true}} -&amp;gt; ...
    {:ok, %Account{initialized: true}} -&amp;gt; ...
    {:error, ...} -&amp;gt; ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code clearly communicates its intent: the only expected outcomes of the &lt;code&gt;setup&lt;/code&gt; function are an account (that is either initialized or suspended) or an error. Further, the case where an account is suspended &amp;quot;supersedes&amp;quot; an initialized account since the pattern match comes first.&lt;/p&gt;
&lt;p&gt;Any other return value isn&amp;#39;t expected and is therefore considered a bug: we explicitly don&amp;#39;t handle those other cases, as we wouldn&amp;#39;t know how to (if we did, they&amp;#39;d have their own &lt;code&gt;case&lt;/code&gt; clause as shown above). In the face of unexpected data, it&amp;#39;s safest to crash so that the OTP system can restart the process from a clean &amp;quot;known good&amp;quot; state rather than propagate dirty data throughout a system.&lt;/p&gt;
&lt;h3&gt;Pattern Matching in Function Heads&lt;/h3&gt;
&lt;p&gt;Pattern matching in function heads is a great way to not only ensure that data conforms to your expectations, but also to communicate your intent.&lt;/p&gt;
&lt;p&gt;Contrast:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp suspend(%Account{} = account)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp suspend(%{suspended: _} = account)
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;These are very different functions: in the first, it&amp;#39;s clear that an &lt;code&gt;Account&lt;/code&gt; is expected, so the &lt;code&gt;account&lt;/code&gt; variable can be safely used in functions expecting an &lt;code&gt;Account&lt;/code&gt; instance, whereas those assurances can&amp;#39;t be made for the second version. In the second example, we&amp;#39;re relying on the presence of the &lt;code&gt;suspended&lt;/code&gt; attribute and a variable name to infer the context. That&amp;#39;s playing with fire: there&amp;#39;s nothing preventing someone from calling the function with a &lt;code&gt;%User{}&lt;/code&gt; struct (assuming it also has a &lt;code&gt;suspended&lt;/code&gt; attribute).&lt;/p&gt;
&lt;p&gt;That said, while matching in function heads is helpful and convenient, make sure you&amp;#39;re not muddying the waters for the sake of convenience. Let&amp;#39;s use the following example to explore the subject, even though it&amp;#39;s not directly related to validation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_call(:checkout, %{workers: [h | t], monitors: monitors}) do
  # ...
end

def handle_call(:checkout, %{workers: [], idle_overflow: [h | t]}) do
  # ...
end

def handle_call(:checkout, %{workers: [], idle_overflow: [],
    overflow: overflow, overflow_max: max, worker_sup: sup,
    spec: spec, monitors: monitors})
  when overflow &amp;lt; max do
    # ...
end

def handle_call(:checkout, %{workers: [], idle_overflow: [],
  overflow: overflow, overflow_max: max, waiting: waiting}) do
# ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A lot of matching is going on here, but how much is to differentiate the function heads, and how much is for convenience (i.e., binding for later use)?&lt;/p&gt;
&lt;p&gt;By leaving only the matches that differentiate the heads and moving other bindings to the function bodies, we can improve readability:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_call(:checkout, %{workers: [_|_]} = state) do
  %{monitors: monitors} = state
  # ...
end

def handle_call(:checkout, %{workers: [], idle_overflow: [_]}) do
  # ...
end

def handle_call(:checkout, %{workers: [], idle_overflow: [],
    overflow: overflow, overflow_max: max} = state) when overflow &amp;lt; max do
  %{worker_sup: sup, spec: spec, monitors: monitors} = state
  # ...
end

def handle_call(:checkout, state) do
  %{workers: [], idle_overflow: [], overflow: overflow,
  overflow_max: max, waiting: waiting} = state
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After refactoring the above (non-validation related) example code, it&amp;#39;s now more obvious that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The first function matches when there are workers in the list.&lt;/li&gt;
&lt;li&gt;The second function matches when there are no workers, but there are values in the &lt;code&gt;idle_overflow&lt;/code&gt; list.&lt;/li&gt;
&lt;li&gt;The third function matches when there are no workers or &lt;code&gt;idle_overflow&lt;/code&gt;, but the overflow hasn&amp;#39;t reached its max level yet.&lt;/li&gt;
&lt;li&gt;The fourth function is for the remaining case.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;#39;ll also note that we&amp;#39;ve gone somewhat overboard on matching here, such as matching on empty worker lists, even though the first function would match in that case. This approach is a bit of defensive programming, as the code will stay functional if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The function clauses are reordered (e.g., during a refactoring), and their ordering importance is overlooked.&lt;/li&gt;
&lt;li&gt;Additional matching is added to the first clause, changing its match semantics. Keeping each function clause responsible for declaring the context it expects makes the code more resilient to change.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avoiding excessive matching in function heads is also the approach &lt;a href=&quot;https://elixirforum.com/t/discussion-incorporating-erlang-otp-21-map-guards-in-elixir/14816/6&quot;&gt;recommended by José Valim&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;FWIW, I tend to use this rule: if the key is necessary when matching the pattern, keep it in the pattern, otherwise, move it to the body. So I end up with code like this:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def some_fun(%{field1: :value} = struct) do
  %{field2: value2, field3: value3} = struct
  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Guard Clauses&lt;/h3&gt;
&lt;p&gt;Guard clauses should be used whenever the definition of &amp;quot;what data is valid&amp;quot; can be tightened to make your code safer by design and to prevent processing unexpected/invalid data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def annotate(%Account{} = account, annotation) when is_binary(annotation)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;case account do
  %Account{payment_method: payment_method} when not is_nil(payment_method) -&amp;gt; ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This same approach can naturally also be used for &lt;code&gt;with&lt;/code&gt; and &lt;code&gt;cond&lt;/code&gt; statements.&lt;/p&gt;
&lt;h3&gt;Custom Guards&lt;/h3&gt;
&lt;p&gt;Declaring custom guards effectively communicates intent and prevents bad data, significantly improving your code.&lt;/p&gt;
&lt;p&gt;First, you must declare the guard in a separate module located outside of the module(s) where you want to use the guard.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Account.Guards do
  defguard is_suspended(account) when is_struct(account, Account) and account.suspended
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now our code is even more expressive:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Account.Guards

case fetch_account(...) do
    %Account{} = account when is_suspended(account) -&amp;gt; ...
    ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Next Up&lt;/h2&gt;
&lt;p&gt;In this post, we looked at how to validate data at the boundary of an Elixir application. We also used a few pattern matching and guard clause techniques to reject bad data.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ve already covered a lot of ground: let&amp;#39;s give it a rest for now. In the next article, we&amp;#39;ll explore a few more options to ensure the data we work with remains squeaky clean, using Ecto.&lt;/p&gt;
&lt;p&gt;See you then!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How To Reduce Reductions in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/09/28/how-to-reduce-reductions-in-elixir.html"/>
    <id>https://blog.appsignal.com/2023/09/28/how-to-reduce-reductions-in-elixir.html</id>
    <published>2023-09-28T00:00:00+00:00</published>
    <updated>2023-09-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how you can use profiling in Elixir to improve how your application code performs.</summary>
    <content type="html">&lt;p&gt;In this article, we&amp;#39;ll show how you can use Elixir&amp;#39;s &lt;code&gt;profile.eprof&lt;/code&gt; mix task to evaluate and improve code performance in your Elixir application. You&amp;#39;ll see how we used the profiling mix task to lower reductions in our &lt;code&gt;instrument/3&lt;/code&gt; function and &lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation/instrumentation.html&quot;&gt;custom instrumentation&lt;/a&gt; functionality, both key parts of our Elixir integration.&lt;/p&gt;
&lt;h2&gt;Our Key Components&lt;/h2&gt;
&lt;p&gt;Before we explain how we used Elixir&amp;#39;s &lt;code&gt;profile.eprof&lt;/code&gt; mix task to improve our &lt;code&gt;instrument&lt;/code&gt; function&amp;#39;s performance, let&amp;#39;s take a moment to understand what &lt;code&gt;profile.eprof&lt;/code&gt; does.&lt;/p&gt;
&lt;h3&gt;Elixir&amp;#39;s &lt;code&gt;profile.eprof&lt;/code&gt; Mix Task&lt;/h3&gt;
&lt;p&gt;Elixir&amp;#39;s &lt;code&gt;profile.eprof&lt;/code&gt; mix task evaluates a piece of code with the &lt;a href=&quot;https://www.erlang.org/doc/man/eprof.html&quot;&gt;eprof&lt;/a&gt; profiling tool enabled. When the code runs, it outputs a time profile report, which shows the number of calls to each function and the amount of time spent in each function.&lt;/p&gt;
&lt;h3&gt;AppSignal&amp;#39;s &lt;code&gt;instrument&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;In its most basic form, the &lt;code&gt;instrument/3&lt;/code&gt; function wraps a piece of code to gain performance insights:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Appsignal.instrument(&amp;quot;slow&amp;quot;, fn -&amp;gt;
  :timer.sleep(1000)
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example above creates a new trace (named &amp;quot;slow&amp;quot; when there&amp;#39;s no current trace) or a child span in a trace that&amp;#39;s already running.&lt;/p&gt;
&lt;p&gt;With AppSignal, we can save and query our application&amp;#39;s performance samples to quickly find similar samples or retrieve older samples when debugging issues.&lt;/p&gt;
&lt;h2&gt;Profiling our &lt;code&gt;instrument&lt;/code&gt; Function&lt;/h2&gt;
&lt;p&gt;To look into the &lt;code&gt;Appsignal.Instrumentation.instrument/3&lt;/code&gt; function, we evaluated the following code snippet through the &lt;code&gt;eprof&lt;/code&gt; task:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix profile.eprof -e &amp;quot;(1..1_000) |&amp;gt; Enum.each(fn _ -&amp;gt; Appsignal.Instrumentation.instrument(\&amp;quot;name\&amp;quot;, \&amp;quot;category\&amp;quot;, fn -&amp;gt; :ok end) end)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For convenience, this is a formatted version of the executed code, which calls the &lt;code&gt;instrument/3&lt;/code&gt; function a thousand times to eliminate any outliers and gauge the average performance of functions called by the instrument function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;(1..1_000)
|&amp;gt; Enum.each(fn _ -&amp;gt;
  Appsignal.Instrumentation.instrument(\&amp;quot;name\&amp;quot;, \&amp;quot;category\&amp;quot;, fn -&amp;gt; :ok end)
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Interpreting Profiling Data&lt;/h2&gt;
&lt;p&gt;Running the profiler produced the following report:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# This report sample has been redacted for brevity

Profile results of #PID&amp;lt;0.315.0&amp;gt;
#                                                        CALLS     %  TIME µS/CALL
Total                                                    11701 100.0 53586    0.46
:application.get_env/2                                    4000  0.90   484    0.12
:ets.lookup/2                                             6000  7.62  4083    0.68
Appsignal.Nif._create_root_span/1                         1000 13.82  7404    7.40
Appsignal.Nif._close_span/1                               1000 29.76 15947   15.95
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The report shows all function calls executed as a result of calling &lt;code&gt;instrument/3&lt;/code&gt;, with the rightmost column showing the time per call in microseconds.&lt;/p&gt;
&lt;p&gt;We then interpreted the profiling data for our &lt;code&gt;instrument&lt;/code&gt; function to understand how our function performed and find places in our code to reduce the number of functions called by our &lt;code&gt;instrument&lt;/code&gt; function.&lt;/p&gt;
&lt;h2&gt;Looking for Reductions&lt;/h2&gt;
&lt;p&gt;Looking back at our report, we can see that the &lt;code&gt;Appsignal.Nif._close_span/1&lt;/code&gt; and &lt;code&gt;Appsignal.Nif._create_root_span/1&lt;/code&gt; functions took the most time, at roughly 16 and 7 microseconds per call, respectively.&lt;/p&gt;
&lt;p&gt;Both functions were called 1,000 times, which made sense because that equated to the number of started and stopped spans. Although some performance gains might be had here, we skipped these function calls, as they were called a reasonable amount of times.&lt;/p&gt;
&lt;p&gt;One place above these is &lt;code&gt;:ets.lookup/2&lt;/code&gt;, which only took 0.68 microseconds per call, but was called 6,000 times, or $6n$ (where $n$ is the number of calls to the &lt;code&gt;instrument/3&lt;/code&gt; function).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def instrument(name, category, fun) do
    instrument(fn span -&amp;gt;
      _ =
        span
        |&amp;gt; @span.set_name(name)
        |&amp;gt; @span.set_attribute(&amp;quot;appsignal:category&amp;quot;, category)

      call_with_optional_argument(fun, span)
    end)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Investigating the &lt;code&gt;instrument/3&lt;/code&gt; function revealed that the &lt;code&gt;Span.set_name/1&lt;/code&gt; function called &lt;code&gt;:ets.lookup/2&lt;/code&gt; twice.&lt;/p&gt;
&lt;h3&gt;Reducing Calls&lt;/h3&gt;
&lt;p&gt;Although AppSignal uses &lt;a href=&quot;https://www.erlang.org/doc/man/ets.html&quot;&gt;ets&lt;/a&gt; internally to store the currently open spans, from checking the configuration, it turned out that the lookups in the &lt;code&gt;set_name/1&lt;/code&gt; function actually happened.&lt;/p&gt;
&lt;p&gt;Internally, the integration checked to see if &lt;code&gt;set_name/1&lt;/code&gt; was active before calling &lt;code&gt;Span.set_name/2&lt;/code&gt;, the function used to set the span name.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def set_name(%Span{reference: reference} = span, name)
    when is_reference(reference) and is_binary(name) do
  if Config.active?() do
    :ok = @nif.set_span_name(reference, name)
    span
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this call wasn&amp;#39;t needed, as calling this function with a &lt;code&gt;nil&lt;/code&gt; value instead of a span is a no-op. When the integration isn&amp;#39;t active, nils are passed around instead of spans so this extra check could be safely removed.&lt;/p&gt;
&lt;p&gt;After making these changes to our code and re-running our profiler, we saw a reduction in the number of calls by $2n$, leaving $4n$ calls to the &lt;code&gt;:ets.lookup/2&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:ets.lookup/2                                             4000  5.06  2458    0.61
Appsignal.Nif._create_root_span/1                         1000 16.30  7922    7.92
Appsignal.Nif._close_span/1                               1000 32.91 16001   16.00
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another lookup was caused by a duplicate call to &lt;code&gt;Application.get_env/1&lt;/code&gt;. Since the application environment is stored in ets as well, each &lt;code&gt;get_env/1&lt;/code&gt; call also does a lookup.&lt;/p&gt;
&lt;p&gt;Previously, the environment was checked twice, in both the &lt;code&gt;active?/0&lt;/code&gt; and &lt;code&gt;valid?/0&lt;/code&gt; functions. If either of these is false, the integration is disabled. The implementation looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def active? do
    :appsignal
    |&amp;gt; Application.get_env(:config, @default_config)
    |&amp;gt; do_active?
  end

  defp do_active?(%{active: true}), do: valid?()
  defp do_active?(_), do: false
  def valid? do
    do_valid?(Application.get_env(:appsignal, :config)[:push_api_key])
  end

  defp do_valid?(push_api_key) when is_binary(push_api_key) do
    !empty?(String.trim(push_api_key))
  end

  defp do_valid?(_push_api_key), do: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exposing &lt;code&gt;valid?/1&lt;/code&gt; (which takes a configuration and only tests if the push API key is present) saved a call to &lt;code&gt;Application.get_env/2&lt;/code&gt;, which internally called another ets lookup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def active? do
    :appsignal
    |&amp;gt; Application.get_env(:config, @default_config)
    |&amp;gt; active?
  end

  defp active?(%{active: true} = config) do
    valid?(config)
  end

  defp active?(_config), do: false

  def valid? do
    :appsignal
    |&amp;gt; Application.get_env(:config)
    |&amp;gt; valid?
  end

  defp valid?(%{push_api_key: key}) when is_binary(key) do
    !(key
      |&amp;gt; String.trim()
      |&amp;gt; empty?())
  end

  defp valid?(_config), do: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having re-run the profiler, we saw the number of calls to &lt;code&gt;:ets.lookup/2&lt;/code&gt; was $3n$:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:erlang.whereis/1                                         4000  1.88   757    0.19
Appsignal.Nif._set_span_attribute_string/3                1000  1.90   766    0.77
Appsignal.Tracer.create_span/3                            1000  2.02   813    0.81
Process.whereis/1                                         4000  2.17   875    0.22
Appsignal.Tracer.running?/0                               4000  2.30   926    0.23
:ets.lookup/2                                             3001  3.91  1576    0.53
Appsignal.Nif._create_root_span/1                         1000 17.12  6903    6.90
Appsignal.Nif._close_span/1                               1000 33.97 13696   13.70
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There was one call to try and find the parent, another call to see if the PID at the time was ignored, and a last call to check if the integration was active at that time.&lt;/p&gt;
&lt;p&gt;It might be possible to remove the check that sees if the integration is active, which happens before starting every span. However, this particular update only consists of performance enhancements, so changes in functionality aren&amp;#39;t included.&lt;/p&gt;
&lt;h3&gt;Removing Unnecessary Calls&lt;/h3&gt;
&lt;p&gt;A line above the &lt;code&gt;:ets.lookup/2&lt;/code&gt; function is &lt;code&gt;Appsignal.Tracer.running?/0&lt;/code&gt;, a function that&amp;#39;s called to ensure ets is running before executing lookups, inserts, and deletions.&lt;/p&gt;
&lt;p&gt;Because ets produces an &lt;code&gt;ArgumentError&lt;/code&gt; when it&amp;#39;s not active, a check was called to ensure the registry was running every time the table was evaluated.&lt;/p&gt;
&lt;p&gt;For example, this included a function to find the current span for a process named &lt;code&gt;Tracer.lookup/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def lookup(pid) do
  if running?(), do: :ets.lookup(@table, pid)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This patch removed those checks and added error handling around each function that called ets, removing &lt;code&gt;Appsignal.Tracer.running?/0&lt;/code&gt; completely:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def lookup(pid) do
  try do
    :ets.lookup(@table, pid)
  rescue
    ArgumentError -&amp;gt; []
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The Final Profile&lt;/h3&gt;
&lt;p&gt;To summarise, we utilized &lt;code&gt;profile.eprof&lt;/code&gt; to locate and reduce $7n$ unnecessary calls, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calls to &lt;code&gt;:ets.lookup/2&lt;/code&gt; from $6n$ to $3n$&lt;/li&gt;
&lt;li&gt;All $4n$ calls to &lt;code&gt;Appsignal.Tracer.running&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This resulted in a small but significant improvement in our &lt;code&gt;instrument&lt;/code&gt; function&amp;#39;s performance.&lt;/p&gt;
&lt;h2&gt;Sample AppSignal&amp;#39;s Performance Monitoring&lt;/h2&gt;
&lt;p&gt;The ability to save and search performance samples is just one of AppSignal&amp;#39;s many developer-driven features designed to help you get the most out of your application&amp;#39;s metrics. Developers say they also love us thanks to our:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Intuitive interface that is easy to navigate.&lt;/li&gt;
&lt;li&gt;Simple and predictable pricing.&lt;/li&gt;
&lt;li&gt;Developer-to-developer support.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you experience any issues when using AppSignal for Elixir, our &lt;a href=&quot;mailto:support@appsignal.com&quot;&gt;support team&lt;/a&gt; is on hand to help! And remember, if you&amp;#39;re new to AppSignal, we&amp;#39;ll welcome you onboard with an exceptionally delicious shipment of stroopwafels 🍪 😋&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Exceptions in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/09/26/an-introduction-to-exceptions-in-elixir.html"/>
    <id>https://blog.appsignal.com/2023/09/26/an-introduction-to-exceptions-in-elixir.html</id>
    <published>2023-09-26T00:00:00+00:00</published>
    <updated>2023-09-26T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s dive into how you can handle exceptions in Elixir.</summary>
    <content type="html">&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; 1 / 0
** (ArithmeticError) bad argument in arithmetic expression: 1 / 0
    :erlang./(1, 0)
    iex:1: (file)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exceptions can also be raised manually:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; raise &amp;quot;BOOM&amp;quot;
** (RuntimeError) BOOM
    iex:1: (file)
&lt;/code&gt;&lt;/pre&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=&quot;https://hexdocs.pm/elixir/1.14/Kernel.html#raise/2&quot;&gt;&lt;code&gt;raise/2&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Math do
  def div(a, b) do
    if b == 0, do: raise ArgumentError, message: &amp;quot;cannot divide by zero&amp;quot;
    a / b
  end
end

iex&amp;gt; Math.div(1, 0)
** (ArgumentError) cannot divide by zero
    iex:4: Math.div/2
    iex:3: (file)
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Math do
  def div(a, b) when b != 0 do
    a / b
  end
end

iex&amp;gt; Math.div(1, 0)
** (FunctionClauseError) no function clause matching in Math.div/2

    The following arguments were given to Math.div/2:

        # 1
        1

        # 2
        0
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
  raise &amp;quot;foo&amp;quot;
rescue
  e in RuntimeError -&amp;gt; IO.inspect(e)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This prints &lt;code&gt;%RuntimeError{message: &amp;quot;foo&amp;quot;}&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
  raise &amp;quot;foo&amp;quot;
rescue
  RuntimeError -&amp;gt; IO.puts(&amp;quot;something bad happened&amp;quot;)
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
  1 / 0
rescue
  e -&amp;gt; IO.inspect(e)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Running the above prints &lt;code&gt;%ArithmeticError{message: &amp;quot;bad argument in arithmetic expression&amp;quot;}&lt;/code&gt;. If you want to perform different actions based on different exceptions, just add more clauses to the rescue branch.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
  1 / 0
rescue
  RuntimeError -&amp;gt; IO.puts(&amp;quot;Runtime Error&amp;quot;)
  ArithmeticError -&amp;gt; IO.puts(&amp;quot;Arithmetic Error&amp;quot;)
  _e -&amp;gt; IO.puts(&amp;quot;Unknown error&amp;quot;)
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Config do
  def get(file) do
    try do
      contents = File.read!(file)
      parse!(contents)
    rescue
      _e -&amp;gt; %{some: &amp;quot;default config&amp;quot;}
    end
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;case File.read(file) do
  {:ok, contents} -&amp;gt; parse!(contents)
  {:error, reason} -&amp;gt; %{some: &amp;quot;default config&amp;quot;}
end
&lt;/code&gt;&lt;/pre&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&amp;#39;s existing stack trace:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
  1 / 0
rescue
  e -&amp;gt;
    IO.puts(Exception.format(:error, e, __STACKTRACE__))
    reraise e, __STACKTRACE__
end
&lt;/code&gt;&lt;/pre&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=&quot;https://appsignal.com/users/sign_up&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule DivisionByZeroError do
  defexception [:message]
end

defmodule Math do
  def div(a, b) do
    try do
      a / b
    rescue
      e in ArithmeticError -&amp;gt;
        reraise DivisionByZeroError, [message: e.message], __STACKTRACE__
    end
  end
end
&lt;/code&gt;&lt;/pre&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&amp;#39;s say that there’s an API that produces numbers and invokes a callback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Producer do
  def produce(callback) do
    Enum.each((1..100) , fn x -&amp;gt; callback.(x) end)
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
  Producer.produce(fn x -&amp;gt;
    if rem(x, 13) == 0 do
      throw(x)
    end
  end)
catch
  x -&amp;gt; IO.puts(&amp;quot;First number divisible by 13 is #{x}&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;producer = Producer.new
try do
  Producer.produce!(producer)
after
  Producer.dispose(producer)
end
&lt;/code&gt;&lt;/pre&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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;try do
  File.read!(&amp;quot;/path/to/file&amp;quot;)
rescue
  File.Error -&amp;gt; :not_found
else
  &amp;quot;a&amp;quot; -&amp;gt; :a
  _other -&amp;gt; :other
end
&lt;/code&gt;&lt;/pre&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=&quot;https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html&quot;&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&amp;#39;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=&quot;https://www.appsignal.com/elixir&quot;&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&amp;#39;s an example of an individual error you can get to from the &amp;quot;Errors&amp;quot; -&amp;gt; &amp;quot;Issue list&amp;quot; in AppSignal for debugging:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/trace-sample.png&quot; alt=&quot;Trace sample&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://docs.appsignal.com/elixir/installation.html&quot;&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&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Phoenix 1.7 for Elixir: Edit a Form in a Modal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/09/12/phoenix-1-7-for-elixir-edit-a-form-in-a-modal.html"/>
    <id>https://blog.appsignal.com/2023/09/12/phoenix-1-7-for-elixir-edit-a-form-in-a-modal.html</id>
    <published>2023-09-12T00:00:00+00:00</published>
    <updated>2023-09-12T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the final part of our series, we&#039;ll implement an edit modal.</summary>
    <content type="html">&lt;p&gt;In part one of this series, we introduced the &lt;code&gt;CoreComponents&lt;/code&gt; that get generated when bootstrapping a new
Phoenix project. In part two, we implemented a create modal.&lt;/p&gt;
&lt;p&gt;Now, we will implement
an edit modal.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can continue following along with our &lt;a href=&quot;https://github.com/Adzz/petacular&quot;&gt;companion repo&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Editing a Form in a Modal&lt;/h2&gt;
&lt;p&gt;You will first notice that each item will need a different changeset. We
want to edit each item, so we need to be able to build a changeset from
a different struct each time.&lt;/p&gt;
&lt;p&gt;You &lt;em&gt;could&lt;/em&gt; do this by iterating over all of the items in &lt;code&gt;mount&lt;/code&gt;
and rendering a different modal for every row, but this won&amp;#39;t work at all. You would have to have
one changeset per assign, which doesn&amp;#39;t work when you have a list to add to. It would
also mean a lot more HTML because you&amp;#39;d render the whole modal once per row. It&amp;#39;s an all-round bad idea.&lt;/p&gt;
&lt;p&gt;Instead, we need a way to build the correct changeset based on the item we click on.
We can do that by using another &lt;code&gt;JS&lt;/code&gt; function — &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.JS.html#push/1&quot;&gt;&lt;code&gt;push&lt;/code&gt;&lt;/a&gt;.
This will push an event to the backend, along with any attributes that we want to send. If we add an edit button per row, the click action can push an event to the backend
with the &lt;code&gt;pet_id&lt;/code&gt; as a param. Then, we can select the pet from the list of assigns and build
a changeset out of it.&lt;/p&gt;
&lt;p&gt;First, add the button to the markup. It might be nice to use an icon for this, so let&amp;#39;s take
a quick detour to icons.&lt;/p&gt;
&lt;h2&gt;Icons in Phoenix&lt;/h2&gt;
&lt;p&gt;Phoenix 1.7 ships with a vendored heroicons library and an &lt;code&gt;&amp;lt;.icon&amp;gt;&lt;/code&gt; component in &lt;code&gt;CoreComponents&lt;/code&gt;.
It works by supplying the name of an icon as a &lt;code&gt;name&lt;/code&gt; attr, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;.icon name=&amp;quot;hero-cpu-chip&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The names for the available icons are the filenames contained in the following
path: &lt;code&gt;assets/vendor/heroicons/optimized/20/solid/&lt;/code&gt;.
Looking at the files doesn&amp;#39;t tell us much about what they look like because we just see svg
markup.&lt;/p&gt;
&lt;p&gt;What would be cool is if we could render a dev-only route that displays all icons on one page.
Then when we consider using an icon, we can go to that page and peruse them all at our leisure.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s add the route:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/router.ex
live(&amp;quot;/storybook&amp;quot;, PetacularWeb.Pages.StoryBookLive, :show)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we can make the necessary &lt;code&gt;PetacularWeb.Pages.StoryBookLive&lt;/code&gt; module. We&amp;#39;ll now write a function that
generates all the icon names from the files in the assets folder, then iterate over them
and create an icon from each one. This will give us a dynamic list of icons to render.&lt;/p&gt;
&lt;p&gt;Here are the &lt;code&gt;icon_names&lt;/code&gt; (this assumes you will start your server from the project&amp;#39;s route):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/story_book_live.ex

defp icon_names() do
  (File.cwd!() &amp;lt;&amp;gt; &amp;quot;/assets/vendor/heroicons/optimized/20/solid&amp;quot;)
  |&amp;gt; Path.expand()
  |&amp;gt; File.ls!()
  |&amp;gt; Enum.map(fn path -&amp;gt;
    &amp;quot;hero-&amp;quot; &amp;lt;&amp;gt; String.replace(path, &amp;quot;.svg&amp;quot;, &amp;quot;&amp;quot;)
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the markup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/story_book_live.ex
@impl true
def render(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;div&amp;gt;
    &amp;lt;h1 class=&amp;quot;text-xl mb-4 font-semibold&amp;quot;&amp;gt;Storytime&amp;lt;/h1&amp;gt;
    &amp;lt;div class=&amp;quot;flex flex-col flex-wrap space-evenly&amp;quot;&amp;gt;
      &amp;lt;%= for icon_name &amp;lt;- icon_names() do %&amp;gt;
        &amp;lt;section class=&amp;quot;p-4 outline outline-1 mb-2 rounded&amp;quot;&amp;gt;
          &amp;lt;h2 class=&amp;quot;font-semibold&amp;quot;&amp;gt;&amp;lt;%= icon_name %&amp;gt;&amp;lt;/h2&amp;gt;
          &amp;lt;div class=&amp;quot;flex space-x-2 p-y-2 p-x-4 mr-2 my-2&amp;quot;&amp;gt;
            &amp;lt;CoreComponents.icon name={icon_name} /&amp;gt;
            &amp;lt;p&amp;gt;&amp;amp;ltCoreComponents.icon name=&amp;quot;&amp;lt;%= icon_name %&amp;gt;&amp;quot;/&amp;amp;gt&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div class=&amp;quot;flex space-x-2 p-y-2 p-x-4 mr-2 my-2&amp;quot;&amp;gt;
            &amp;lt;CoreComponents.icon name={icon_name&amp;lt;&amp;gt; &amp;quot;-mini&amp;quot;} /&amp;gt;
            &amp;lt;p&amp;gt;&amp;amp;ltCoreComponents.icon name=&amp;quot;&amp;lt;%= icon_name %&amp;gt;-mini&amp;quot;/&amp;amp;gt&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div class=&amp;quot;flex space-x-2 p-y-2 p-x-4 mr-2 my-2&amp;quot;&amp;gt;
            &amp;lt;CoreComponents.icon name={icon_name&amp;lt;&amp;gt; &amp;quot;-solid&amp;quot;} /&amp;gt;
            &amp;lt;p&amp;gt;&amp;amp;ltCoreComponents.icon name=&amp;quot;&amp;lt;%= icon_name %&amp;gt;-solid&amp;quot;/&amp;amp;gt&amp;lt;/p&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/section&amp;gt;
      &amp;lt;% end %&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is one more thing to do, though. Tailwind will purge all classes it doesn&amp;#39;t see
being used when the app is built. Usually, this is great because it means the bundle size is
smaller, with more lightweight pages. However, here, it is going to bite us. When you
refer to classes dynamically, Tailwind doesn&amp;#39;t see those classes being used, so it purges them. &lt;a href=&quot;https://tailwindcss.com/docs/content-configuration#dynamic-class-names&quot;&gt;Tailwind&amp;#39;s docs warn about this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We need to tell Tailwind &lt;em&gt;not&lt;/em&gt; to purge all the icon modules so we can render them. We do that by adding a line of config into &lt;code&gt;tailwind.config.js&lt;/code&gt;, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;safelist: [{ pattern: /hero\-.*/ }],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can head to &lt;code&gt;http://localhost:4000/dev/storybook&lt;/code&gt; and see all the icons. See
&lt;a href=&quot;https://github.com/Adzz/petacular/commit/91a0ff0e3af688a47864dc030a83b0f705e8f021&quot;&gt;this commit&lt;/a&gt;
for all of the changes.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Back to Editing Our Form&lt;/h3&gt;
&lt;p&gt;Okay, now we can select our edit icon and put it on the page.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;PetacularWeb.CoreComponents.icon name=&amp;quot;hero-pencil-square-solid&amp;quot; class=&amp;quot;mr-2&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will put this in a button and add a &lt;code&gt;phx-click&lt;/code&gt; that opens our edit modal for us. All
this can live in the &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/pages/home_live.ex&quot;&gt;homepage&lt;/a&gt; we used in parts one and two.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex

  @impl true
  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    ...

    &amp;lt;div class=&amp;quot;w-50 mb-4&amp;quot;&amp;gt;
      &amp;lt;%= for pet &amp;lt;- @pets do %&amp;gt;
        &amp;lt;div class=&amp;quot;flex&amp;quot;&amp;gt;
          &amp;lt;button phx-click={open_edit_modal(pet.id)}&amp;gt;
            &amp;lt;PetacularWeb.CoreComponents.icon name=&amp;quot;hero-pencil-square-solid&amp;quot; class=&amp;quot;mr-2&amp;quot; /&amp;gt;
          &amp;lt;/button&amp;gt;
          &amp;lt;p&amp;gt;Name: &amp;lt;span class=&amp;quot;font-semibold&amp;quot;&amp;gt;&amp;lt;%= pet.name %&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;% end %&amp;gt;
    &amp;lt;/div&amp;gt;

    ...
    &amp;quot;&amp;quot;&amp;quot;
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to create our &lt;code&gt;Edit&lt;/code&gt; modal. This will be similar to our &lt;code&gt;Create&lt;/code&gt; modal, but a bit different, so we&amp;#39;ll just create a new modal.&lt;/p&gt;
&lt;p&gt;We can put this in our &lt;code&gt;~H&lt;/code&gt; component just before the other modal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex

  @impl true
  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;PetacularWeb.CoreComponents.modal id=&amp;quot;edit_modal&amp;quot;&amp;gt;
    &amp;lt;h2&amp;gt;Edit a pet.&amp;lt;/h2&amp;gt;

    &amp;lt;PetacularWeb.CoreComponents.simple_form for={@edit_changeset} phx-submit=&amp;quot;edit_pet&amp;quot;&amp;gt;
      &amp;lt;PetacularWeb.CoreComponents.input
        label=&amp;quot;Name&amp;quot;
        id=&amp;quot;edit_name&amp;quot;
        field={@edit_changeset[:name]}
        value={@edit_changeset[:name].value}
      /&amp;gt;
      &amp;lt;:actions&amp;gt;
        &amp;lt;PetacularWeb.CoreComponents.button&amp;gt;
          Save
        &amp;lt;/PetacularWeb.CoreComponents.button&amp;gt;
      &amp;lt;/:actions&amp;gt;
    &amp;lt;/PetacularWeb.CoreComponents.simple_form&amp;gt;
  &amp;lt;/PetacularWeb.CoreComponents.modal&amp;gt;
    ...
    &amp;quot;&amp;quot;&amp;quot;
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to add a changeset to the assigns. Initially, we can put any changeset in mount because when we open the modal, we are going to seed it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex

@impl true
def mount(_params, _session, socket) do
  default_assigns = %{
    pets: Repo.all(Petacular.Pet),
    edit_form: Phoenix.Component.to_form(Petacular.Pet.create_changeset(%{})),
    create_form: Phoenix.Component.to_form(Petacular.Pet.create_changeset(%{}))
  }

  {:ok, assign(socket, default_assigns)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Add the &lt;code&gt;open_edit_modal&lt;/code&gt; Function&lt;/h2&gt;
&lt;p&gt;Now let&amp;#39;s implement the &lt;code&gt;open_edit_modal&lt;/code&gt; function. This has to do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the modal.&lt;/li&gt;
&lt;li&gt;Trigger a message to the backend so we can seed the changeset.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex

defp open_edit_modal(pet_id) do
  %JS{}
  |&amp;gt; JS.push(&amp;quot;open_edit_modal&amp;quot;, value: %{pet_id: pet_id})
  |&amp;gt; PetacularWeb.CoreComponents.show_modal(&amp;quot;edit_modal&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The handler for this event needs to select the relevant pet from the list of pets and
put that into the changeset:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex

@impl true
def handle_event(&amp;quot;open_edit_modal&amp;quot;, %{&amp;quot;pet_id&amp;quot; =&amp;gt; id}, socket) do
  pet = Enum.find(socket.assigns.pets, &amp;amp;(&amp;amp;1.id == id))

  new_assigns = %{
    edit_form: Phoenix.Component.to_form(Petacular.Pet.edit_changeset(%{}, pet))
  }

  {:noreply, assign(socket, new_assigns)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we open the modal, the page will re-render the form because the changeset has changed,
and the form will be seeded with the correct data. We can verify this by using
&lt;code&gt;|&amp;gt; IO.inspect(limit: :infinity, label: &amp;quot;&amp;quot;)&lt;/code&gt; on the form value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;value={@edit_changeset[:name].value |&amp;gt; IO.inspect(limit: :infinity, label: &amp;quot;edit for name:&amp;quot;)}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Debugging an Issue with the &lt;code&gt;open_edit_modal&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;If you open the modal, you will see the correct value printed. But there is a problem — it&amp;#39;s
not showing on the page! What on earth could be the issue? This one is a doozy, so I will
save you some hours of debugging.&lt;/p&gt;
&lt;p&gt;The function that we use to &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L591&quot;&gt;open our modal&lt;/a&gt; has this line, which focuses the first &amp;quot;focussable&amp;quot;
element in the modal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;|&amp;gt; JS.focus_first(to: &amp;quot;##{id}-content&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is done for accessibility, and so is generally a good idea.&lt;/p&gt;
&lt;p&gt;The input happens to be the first focussable thing in our edit form. Phoenix also ensures
that the client is the source of truth for &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/form-bindings.html#javascript-client-specifics&quot;&gt;an input&amp;#39;s value&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For any given input with focus, LiveView will never overwrite the input&amp;#39;s current value, even if it deviates from the server&amp;#39;s rendered updates.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what happens in our case? We push an asynchronous message to the backend, which changes an assign (the edit
form), causing a re-render — &lt;code&gt;|&amp;gt; JS.push(&amp;quot;open_edit_modal&amp;quot;, value: %{pet_id: pet_id})&lt;/code&gt;. Then we
open the modal with JavaScript, but because the message to the server is async, the modal
opens &lt;em&gt;before&lt;/em&gt; we get a reply. The first focussable element is the input field, so that gets
focus, then the server responds. This would normally re-render the input field, but now won&amp;#39;t, because the input has focus!&lt;/p&gt;
&lt;h3&gt;Fixing the Issue&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ve done everything right, yet are left adrift. What are our options?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Remove the auto-focus capabilities of the modal.&lt;/li&gt;
&lt;li&gt;Have the edit modal focus on something that is not the input first.&lt;/li&gt;
&lt;li&gt;Somehow make the form opening synchronous to the server message.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I honestly don&amp;#39;t know which is better, but let&amp;#39;s reason them out. One is easy to do — just &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L600&quot;&gt;remove this line&lt;/a&gt;
from the &lt;code&gt;show_modal&lt;/code&gt; function — but may have accessibility implications, which makes it a non-starter.&lt;/p&gt;
&lt;p&gt;The second option seems reasonable at first. We could maybe set the &lt;code&gt;tabindex&lt;/code&gt; on the heading,
but &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Keyboard&quot;&gt;mdn&lt;/a&gt;
recommends the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If an element can be focused using the keyboard, then it should be interactive; that is, the user should be able to do something to it and produce a change of some kind (for example, activating a link or changing an option).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So that&amp;#39;s out.&lt;/p&gt;
&lt;p&gt;The third option is possible, but requires some ceremony. Instead of opening the modal with JS, you could have the backend trigger a JS event that opens the modal when it&amp;#39;s finished
seeding the changeset. That requires adding a handler in JS to listen for the event
and also means that the modal open is slower, because it requires at least one round trip to
the server. For me, that is out as well.&lt;/p&gt;
&lt;p&gt;The solution? A secret fourth option — set the value of the field with JS. This means
the field will open quickly, be set to the correct value, and auto-focus.&lt;/p&gt;
&lt;p&gt;To support that, we alter our &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/pages/home_live.ex#L74&quot;&gt;&lt;code&gt;open_edit_modal&lt;/code&gt;&lt;/a&gt;
function to accept the name, then use &lt;code&gt;JS.set_attribute&lt;/code&gt; to set the field value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...
&amp;lt;button phx-click={open_edit_modal(pet.id, pet.name)}&amp;gt;
  &amp;lt;PetacularWeb.CoreComponents.icon name=&amp;quot;hero-pencil-square-solid&amp;quot; class=&amp;quot;mr-2&amp;quot; /&amp;gt;
&amp;lt;/button&amp;gt;
...

defp open_edit_modal(pet_id, pet_name) do
  %JS{}
  |&amp;gt; JS.push(&amp;quot;open_edit_modal&amp;quot;, value: %{pet_id: pet_id})
  |&amp;gt; JS.set_attribute({&amp;quot;value&amp;quot;, pet_name}, to: &amp;quot;#edit_name&amp;quot;)
  |&amp;gt; PetacularWeb.CoreComponents.show_modal(&amp;quot;edit_modal&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Implementing the Update in Our Phoenix Application&lt;/h2&gt;
&lt;p&gt;Now the only thing left to do is implement the &lt;code&gt;edit_pet&lt;/code&gt; handler. This is similar to the
create version, where we flash an error and close the modal on success. We first want to
select the pet we are editing, which means we need the pet&amp;#39;s id. How can we get that?&lt;/p&gt;
&lt;p&gt;The easiest way is to use a hidden input on the form. That way, when the form is submitted, the pet id will also be sent. To do that, we need to add the hidden input:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= Phoenix.HTML.Form.hidden_input(f, :id, id: &amp;quot;edit_pet_id_input&amp;quot;) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And set the value when we open the modal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp open_edit_modal(pet_id, pet_name) do
  %JS{}
  |&amp;gt; JS.push(&amp;quot;open_edit_modal&amp;quot;, value: %{pet_id: pet_id})
  |&amp;gt; JS.set_attribute({&amp;quot;value&amp;quot;, pet_name}, to: &amp;quot;#edit_name&amp;quot;)
  |&amp;gt; JS.set_attribute({&amp;quot;value&amp;quot;, pet_id}, to: &amp;quot;#edit_pet_id_input&amp;quot;)
  # ^^^ this line ^^^^
  |&amp;gt; PetacularWeb.CoreComponents.show_modal(&amp;quot;edit_modal&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will see the id of the pet appear in the params, allowing us to select
the pet we are editing from the assigns:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@impl true
def handle_event(&amp;quot;edit_pet&amp;quot;, %{&amp;quot;pet&amp;quot; =&amp;gt; %{&amp;quot;id&amp;quot; =&amp;gt; id} = params}, socket) do
  pet = Enum.find(socket.assigns.pets, &amp;amp;(&amp;amp;1.id == String.to_integer(id)))

  case Repo.insert(Petacular.Pet.edit_changeset(params, pet)) do
    {:error, message} -&amp;gt;
      {:noreply, socket |&amp;gt; put_flash(:error, inspect(message))}

    {:ok, _} -&amp;gt;
      new_assigns = %{
        pets: Repo.all(Petacular.Pet),
        edit_form: Phoenix.Component.to_form(Petacular.Pet.create_changeset(%{}))
      }

      socket =
        socket
        |&amp;gt; assign(new_assigns)
        |&amp;gt; push_event(&amp;quot;close_modal&amp;quot;, %{to: &amp;quot;#close_modal_btn_edit_modal&amp;quot;})

      {:noreply, socket}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See &lt;a href=&quot;https://github.com/Adzz/petacular/commit/364bec4c35c796bcd19f63ccd42ad230c0ed4afc&quot;&gt;this commit&lt;/a&gt;
for all the relevant changes.&lt;/p&gt;
&lt;p&gt;And with that, we are done!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;This concludes our three-part series in which we took a fresh Phoenix 1.7 application and built a create and edit modal for
it.&lt;/p&gt;
&lt;p&gt;Hopefully, this gives you some new ideas you can extend and implement for your own apps.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Writing a Custom Credo Check in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/08/29/writing-a-custom-credo-check-in-elixir.html"/>
    <id>https://blog.appsignal.com/2023/08/29/writing-a-custom-credo-check-in-elixir.html</id>
    <published>2023-08-29T00:00:00+00:00</published>
    <updated>2023-08-29T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s run through the process of creating  a Credo check in Elixir.</summary>
    <content type="html">&lt;p&gt;Static code analysis is an important tool to ensure a project meets the right code standards and quality. In Elixir, the most
popular package for this is Credo. Not only does it offer dozens of pre-made checks, but it also allows you to create your own.&lt;/p&gt;
&lt;p&gt;In this article, we will walk you through creating a Credo check. We will see how to write the code, enable the check in the Credo config, and make it nice to use.&lt;/p&gt;
&lt;p&gt;Let’s start!&lt;/p&gt;
&lt;h2&gt;Why Create Credo Checks?&lt;/h2&gt;
&lt;p&gt;There are many things you can create Credo checks for. Some examples are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To check a timestamp in migration files and see if it shows the correct date&lt;/li&gt;
&lt;li&gt;To forbid calling business logic from migration files&lt;/li&gt;
&lt;li&gt;To disallow referencing or aliasing &lt;code&gt;MyAppWeb&lt;/code&gt; modules from &lt;code&gt;MyApp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;To ensure some naming conventions, for example, forbidding the &lt;code&gt;is_&lt;/code&gt; prefix for functions (prefer &lt;code&gt;active?&lt;/code&gt; to &lt;code&gt;is_active&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let&amp;#39;s dive into a real-world example with an Elixir app.&lt;/p&gt;
&lt;h2&gt;Getting Started with Credo for Elixir&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s first add Credo to an Elixir project. We will start with a
new empty mix project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ mix new my_app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we will &lt;code&gt;cd&lt;/code&gt; into the newly created &lt;code&gt;my_app&lt;/code&gt; and add Credo to the dependencies in &lt;code&gt;mix.exs&lt;/code&gt;, so it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [{:credo, &amp;quot;~&amp;gt; 1.7&amp;quot;, only: [:dev, :test], runtime: false}]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, we can run &lt;code&gt;mix deps.get&lt;/code&gt;, then run Credo with &lt;code&gt;mix credo&lt;/code&gt;. The output is not very interesting —
our project is empty, so it does not violate anything. Let&amp;#39;s quickly change that. Open &lt;code&gt;lib/my_app.ex&lt;/code&gt; and change
it to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp do
  @moduledoc &amp;quot;&amp;quot;&amp;quot;
  Documentation for `MyApp`.
  &amp;quot;&amp;quot;&amp;quot;

  def test do
    x = 1; y = 2
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when we run &lt;code&gt;mix credo&lt;/code&gt;, we get a nice error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;Checking 3 source files ...

  Code Readability
┃
┃ [R] ↗ Don&amp;#39;t use ; to separate statements and expressions
┃       lib/my_app.ex:7:10 #(MyApp.test)

Please report incorrect results: https://github.com/rrrene/credo/issues

Analysis took 0.1 seconds (0.07s to load, 0.1s running 55 checks on 3 files)
3 mods/funs, found 1 code readability issue.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we are unsure what that means, we can ask for details:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ mix credo explain lib/my_app.ex:7

  MyApp
┃
┃   [R] Category: readability
┃    ↗  Priority: high
┃
┃       Don&amp;#39;t use ; to separate statements and expressions
┃       lib/my_app.ex:7:10 (MyApp.test)
┃
┃    __ CODE IN QUESTION
┃
┃     5
┃     6   def test do
┃     7     x = 1; y = 2
┃                ^
┃     8   end
┃     9 end
┃
┃    __ WHY IT MATTERS
┃
┃       Don&amp;#39;t use ; to separate statements and expressions.
┃       Statements and expressions should be separated by lines.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output above is clipped. Run it yourself to read the whole explanation and to see it in color too!&lt;/p&gt;
&lt;h2&gt;Anatomy of a Credo Check&lt;/h2&gt;
&lt;p&gt;Credo checks are divided into categories. The one above falls under &amp;quot;readability&amp;quot;. We also have &amp;quot;consistency&amp;quot;,
&amp;quot;refactor&amp;quot;, &amp;quot;design&amp;quot;, and &amp;quot;warning&amp;quot;. Each check also has its own priority (set to &amp;#39;high&amp;#39; in the example above), name, and explanation.&lt;/p&gt;
&lt;p&gt;The check is an Elixir module. Built-in checks are kept in the Credo repository.&lt;/p&gt;
&lt;p&gt;The check in question is defined in
&lt;a href=&quot;https://github.com/rrrene/credo/blob/master/lib/credo/check/readability/semicolons.ex&quot;&gt;this file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It starts with &lt;code&gt;use Credo.Check&lt;/code&gt;, followed by quite a lot of passed configs. An identifier of
a check is defined, its priority, tags, and a long string with an explanation — we saw this when we ran &lt;code&gt;mix credo explain&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is followed by a definition of the &lt;code&gt;run&lt;/code&gt; function, taking a source file and some params as input, as the entry
point for the check. It will run for every file where the check is enabled, passing the file as the first argument.&lt;/p&gt;
&lt;p&gt;Other than that, the check defines a bunch of private functions. Three versions of &lt;code&gt;collect_issues&lt;/code&gt; are responsible for
finding lines with a semicolon token. And if found, the issues accumulator is updated with a relevant line and
column number, as well as an appropriate message and trigger.&lt;/p&gt;
&lt;p&gt;An important thing to note is &lt;code&gt;Credo.Code.to_tokens(source_file)&lt;/code&gt; — it splits the source file contents into tokens and
feeds those tokens to the &lt;code&gt;collect_issues&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;If we put &lt;code&gt;IO.inspect&lt;/code&gt; there, we see that our file from the above listing looks like this (parsed as tokens):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;[
  {:identifier, {1, 1, &amp;#39;defmodule&amp;#39;}, :defmodule},
  {:alias, {1, 11, &amp;#39;MyApp&amp;#39;}, :MyApp},
  {:do, {1, 17, nil}},
  {:eol, {1, 19, 1}},
  {:at_op, {2, 3, nil}, :@},
  {:identifier, {2, 4, &amp;#39;moduledoc&amp;#39;}, :moduledoc},
  {:bin_heredoc, {2, 14, nil}, 2, [&amp;quot;Documentation for `MyApp`.\n&amp;quot;]},
  {:eol, {4, 6, 2}},
  {:identifier, {6, 3, &amp;#39;def&amp;#39;}, :def},
  {:do_identifier, {6, 7, &amp;#39;test&amp;#39;}, :test},
  {:do, {6, 12, nil}},
  {:eol, {6, 14, 1}},
  {:identifier, {7, 5, &amp;#39;x&amp;#39;}, :x},
  {:match_op, {7, 7, nil}, :=},
  {:int, {7, 9, 1}, &amp;#39;1&amp;#39;},
  {:&amp;quot;;&amp;quot;, {7, 10, 0}},
  {:identifier, {7, 12, &amp;#39;y&amp;#39;}, :y},
  {:match_op, {7, 14, nil}, :=},
  {:int, {7, 16, 2}, &amp;#39;2&amp;#39;},
  {:eol, {7, 17, 1}},
  {:end, {8, 3, nil}},
  {:eol, {8, 7, 1}},
  {:end, {9, 1, nil}},
  {:eol, {9, 4, 1}}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Indeed, we have a &lt;code&gt;{:&amp;quot;;&amp;quot;, {7, 10, 0}}&lt;/code&gt; token, which is easy to match. It means that there is a semicolon in
line 7, column 10 — which is exactly where the semicolon is in our code.&lt;/p&gt;
&lt;p&gt;Armed with that knowledge, we can start writing our own check.&lt;/p&gt;
&lt;h2&gt;Our Very Own Credo Check in Elixir&lt;/h2&gt;
&lt;p&gt;We will write a check forbidding us from doing &amp;quot;bare imports&amp;quot;. What I mean by that is calls like &lt;code&gt;import Ecto.Changeset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why should we do this, though? Well, when you import the entire &lt;code&gt;Ecto.Changeset&lt;/code&gt; module, and then use specific functions from that
module, it can be hard for future collaborators (or future you) to determine where those functions were first defined.&lt;/p&gt;
&lt;p&gt;However, in Elixir, you can specify a list of particular functions to import. So this would be fine:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Ecto.Changeset, only: [cast: 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To start, we will add a &amp;quot;bare&amp;quot; import statement to our &lt;code&gt;MyApp&lt;/code&gt; code. Remember to also add Ecto to the dependencies,
otherwise the code will not compile.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp do
  @moduledoc false
  import Ecto.Changeset
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need the actual check too. Credo offers a mix task to generate a new check. It adds example content, which might
sometimes be useful. For our purpose, it would be confusing to start with the example code and then remove most of it, so we will build our check from scratch.&lt;/p&gt;
&lt;p&gt;If you want to use the generator in the future, here&amp;#39;s how:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ mix credo.gen.check lib/credo/precise_imports.ex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead, we will create the file skeleton ourselves. In the same location, let&amp;#39;s start with this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Credo.Check.Readability.PreciseImports do
  @moduledoc false
  use Credo.Check,
    base_priority: :medium,
    explanations: [check: &amp;quot;Use :only with all imports&amp;quot;]

  @impl true
  def run(source_file, params) do
    []
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Write Some Tests in Credo&lt;/h3&gt;
&lt;p&gt;To check if it works, we need to write some tests. Luckily for us, Credo makes this really easy.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Credo.Check.Readability.PreciseImportsTest do
  use Credo.Test.Case

  @described_check Credo.Check.Readability.PreciseImports

  test &amp;quot;it should not raise issues&amp;quot; do
    &amp;quot;&amp;quot;&amp;quot;
    defmodule TestModule do
      import MyApp.Helpers, only: [hello: 0]
    end
    &amp;quot;&amp;quot;&amp;quot;
    |&amp;gt; to_source_file()
    |&amp;gt; run_check(@described_check)
    |&amp;gt; refute_issues()
  end

  test &amp;quot;it should report a violation&amp;quot; do
    &amp;quot;&amp;quot;&amp;quot;
    defmodule TestModule do
      import MyApp.Helpers
    end
    &amp;quot;&amp;quot;&amp;quot;
    |&amp;gt; to_source_file()
    |&amp;gt; run_check(@described_check)
    |&amp;gt; assert_issue()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to start the Credo application in our &lt;code&gt;test_helper.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Credo.Application.start([], [])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have one test passing and one failing because we have not implemented the check yet. How should we
do that?&lt;/p&gt;
&lt;p&gt;If we try to use &lt;code&gt;to_tokens&lt;/code&gt;, it might be quite hard to catch the &lt;code&gt;import&lt;/code&gt; without the &lt;code&gt;only&lt;/code&gt; option.
Tokens are always a flat list of, well, tokens. It&amp;#39;s hard to pattern match to some cases, based on the option
passed to the &lt;code&gt;import&lt;/code&gt; call.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;[
  {:identifier, {1, 1, &amp;#39;defmodule&amp;#39;}, :defmodule},
  {:alias, {1, 11, &amp;#39;TestModule&amp;#39;}, :TestModule},
  {:do, {1, 22, nil}},
  {:eol, {1, 24, 1}},
  {:identifier, {2, 3, &amp;#39;import&amp;#39;}, :import},
  {:alias, {2, 10, &amp;#39;Ecto&amp;#39;}, :MyApp},
  {:., {2, 15, nil}},
  {:alias, {2, 16, &amp;#39;Changeset&amp;#39;}, :Helpers},
  {:eol, {2, 23, 1}},
  {:end, {3, 1, nil}},
  {:eol, {3, 4, 1}}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ASTs in Elixir&lt;/h3&gt;
&lt;p&gt;We need a different approach. Fortunately, Elixir provides a &amp;quot;smarter&amp;quot; representation of the code as an AST
(abstract syntax tree). We can get it by using &lt;code&gt;Credo.Code.ast&lt;/code&gt;. Here is how the results look for our simple module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;&amp;gt; source = &amp;quot;&amp;quot;&amp;quot;
defmodule TestModule do
  import Ecto.Changeset
end
&amp;quot;&amp;quot;&amp;quot;
&amp;gt; Credo.Code.ast(source)
{:ok,
 {:defmodule, [line: 1, column: 1],
  [
    {:__aliases__, [line: 1, column: 11], [:TestModule]},
    [
      do: {:import, [line: 2, column: 3],
       [{:__aliases__, [line: 2, column: 10], [:Ecto, :Changeset]}]}
    ]
  ]}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And when we specify import with &lt;code&gt;only: [cast: 4]&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;&amp;gt; source = &amp;quot;&amp;quot;&amp;quot;
defmodule TestModule do
  import Ecto.Changeset, only: [cast: 4]
end
&amp;quot;&amp;quot;&amp;quot;
&amp;gt; Credo.Code.ast(source)
{:ok,
 {:defmodule, [line: 1, column: 1],
  [
    {:__aliases__, [line: 1, column: 11], [:TestModule]},
    [
      do: {:import, [line: 2, column: 3],
       [
         {:__aliases__, [line: 2, column: 10], [:Ecto, :Changeset]},
         [only: [cast: 4]]
       ]}
    ]
  ]}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This might look quite difficult to understand. Fortunately, Credo offers a &lt;code&gt;prewalk&lt;/code&gt; function to make our job easier.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;prewalk&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s change our check to use the &lt;code&gt;prewalk&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Credo.Check.Readability.PreciseImports do
  @moduledoc false
  use Credo.Check,
    base_priority: :normal,
    explanations: [check: &amp;quot;Use :only with all imports&amp;quot;]

  @impl true
  def run(source_file, params) do
    source_file
    |&amp;gt; Credo.Code.prewalk(&amp;amp;traverse(&amp;amp;1, &amp;amp;2, IssueMeta.for(source_file, params)))
  end

  defp traverse(ast, issues, issue_meta), do: {ast, add_issue(issues, issue(ast, issue_meta))}

  defp add_issue(issues, nil), do: issues
  defp add_issue(issues, issue), do: [issue | issues]

  defp issue({:import, meta, [{:__aliases__, _, _}]}, issue_meta) do
    issue_for(issue_meta, meta[:line])
  end

  defp issue({:import, meta, [{:__aliases__, _, _}, opts]}, issue_meta) do
    if Keyword.has_key?(opts, :only), do: nil, else: issue_for(issue_meta, meta[:line])
  end

  defp issue(_, _), do: nil

  defp issue_for(issue_meta, line_no) do
    format_issue(
      issue_meta,
      message: &amp;quot;Use :only with import statements&amp;quot;,
      line_no: line_no
    )
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s break this down.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def run(source_file, params) do
  source_file
  |&amp;gt; Credo.Code.prewalk(&amp;amp;traverse(&amp;amp;1, &amp;amp;2, IssueMeta.for(source_file, params)))
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We take the &lt;code&gt;source_file&lt;/code&gt; here and feed it to the &lt;code&gt;Credo.Code.prewalk&lt;/code&gt; function. This accepts a function that
is called for every node of the AST we traverse. If we were to log what arguments are passed by the &lt;code&gt;prewalk&lt;/code&gt; function, the second one is an accumulator where we should store a list of offences detected by our check (starting with an empty list).&lt;/p&gt;
&lt;p&gt;As for the first argument, it&amp;#39;s the current node of the AST. In the first run, it will be the whole tree, and in the
subsequent calls, it will pass the inner leaves.&lt;/p&gt;
&lt;p&gt;The first run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;{:defmodule, [line: 1, column: 1],
 [
   {:__aliases__, [line: 1, column: 11], [:TestModule]},
   [
     do: {:import, [line: 2, column: 3],
      [
        {:__aliases__, [line: 2, column: 10], [:MyApp, :Helpers]},
        [only: [hello: 0]]
      ]}
   ]
 ]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Second:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;{:__aliases__, [line: 1, column: 11], [:TestModule]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the third step, it&amp;#39;s just the name of the module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;:TestModule
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;#39;s nothing here to go deeper into, so we go to the next &amp;quot;sibling&amp;quot; node:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;[
  do: {:import, [line: 2, column: 3],
   [
     {:__aliases__, [line: 2, column: 10], [:MyApp, :Helpers]},
     [only: [hello: 0]]
   ]}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will go down deeper, but at some point before it finishes, the argument will be very useful for us. It will look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;{:import, [line: 2, column: 3],
 [{:__aliases__, [line: 2, column: 10], [:MyApp, :Helpers]}, [only: [hello: 0]]]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we move to the &lt;code&gt;traverse&lt;/code&gt; function, there is also an &lt;code&gt;IssueMeta.for(source_file, params)&lt;/code&gt; call. In fact, this is
&lt;a href=&quot;https://hexdocs.pm/credo/Credo.IssueMeta.html#for/2&quot;&gt;&lt;code&gt;Credo.IssueMeta.for/2&lt;/code&gt;&lt;/a&gt;, but &lt;code&gt;use Credo.Check&lt;/code&gt; creates an alias for it.
The function returns a metadata structure, which will help Credo identify in which file the issue is found. We don&amp;#39;t
need to know more about it, just use it: pass it to &lt;code&gt;traverse&lt;/code&gt; and then to &lt;code&gt;issue&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp traverse(ast, issues, issue_meta), do: {ast, add_issue(issues, issue(ast, issue_meta))}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;The &lt;code&gt;traverse&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;As we know from before, &lt;code&gt;traverse&lt;/code&gt; accepts an AST and accumulator of found issues (initially empty). The third argument
is the &lt;code&gt;issue_meta&lt;/code&gt; required by Credo.&lt;/p&gt;
&lt;p&gt;Implementing this function is simple: it returns the same AST node (so &lt;code&gt;prewalk&lt;/code&gt; can take it and traverse it
further) and changes the accumulator (or not) using the &lt;code&gt;add_issue&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp add_issue(issues, nil), do: issues
defp add_issue(issues, issue), do: [issue | issues]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, if the &amp;quot;current issue&amp;quot; is a &lt;code&gt;nil&lt;/code&gt;, just return the list of issues. But if it&amp;#39;s something else,
prepend it to the list.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;issue&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;Now we need to look at the &lt;code&gt;issue&lt;/code&gt; function, which is finally responsible for detecting the actual issue. This
function takes the AST node as the first argument and Credo&amp;#39;s &lt;code&gt;issue_meta&lt;/code&gt; as the second. If we detect an issue, it returns
the relevant issue information (&lt;code&gt;issue_for&lt;/code&gt;, or &lt;code&gt;nil&lt;/code&gt; otherwise).&lt;/p&gt;
&lt;p&gt;Remember how the AST of an import with the &lt;code&gt;only&lt;/code&gt; option looks? We will match against it now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;{:import, [line: 2, column: 3],
 [{:__aliases__, [line: 2, column: 10], [:MyApp, :Helpers]}, [only: [hello: 0]]]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first &amp;quot;wrong&amp;quot; variant is when no options are passed to the &lt;code&gt;import&lt;/code&gt; statement (&lt;code&gt;import Ecto.Changeset&lt;/code&gt;) at all.
We will match with this and return a non-&lt;code&gt;nil&lt;/code&gt; result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp issue({:import, meta, [{:__aliases__, _, _}]}, issue_meta) do
  issue_for(issue_meta, meta[:line])
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another possible violation is when options are given, but they don&amp;#39;t contain &lt;code&gt;only&lt;/code&gt;, for example: &lt;code&gt;import Ecto.Changeset, except: [from: 3]&lt;/code&gt;.
We match the &lt;code&gt;opts&lt;/code&gt; in the function definition, and then check if it contains the required key. If not,
we add an issue.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp issue({:import, meta, [{:__aliases__, _, _}, opts]}, issue_meta) do
  if Keyword.has_key?(opts, :only), do: nil, else: issue_for(issue_meta, meta[:line])
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need one definition for all other cases. We pass the AST nodes to the function, including ones not related to the import. These nodes cannot be the cause of the issue we are looking for, so it&amp;#39;s a simple &amp;quot;catch-all&amp;quot;
variant:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp issue(_, _), do: nil
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last thing in the module is the &lt;code&gt;issue_for&lt;/code&gt; functions. These take the meta generated by &lt;code&gt;IssueMeta.for&lt;/code&gt; and pass it to Credo&amp;#39;s
&lt;code&gt;format_issue&lt;/code&gt; function, along with the message and the line number.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp issue_for(issue_meta, line_no) do
  format_issue(
    issue_meta,
    message: &amp;quot;Use :only with import statements&amp;quot;,
    line_no: line_no
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can run our tests now to verify that they pass: the check detects issues correctly.&lt;/p&gt;
&lt;h3&gt;Enabling the Credo Check in Elixir&lt;/h3&gt;
&lt;p&gt;As we know that our check works fine (because our tests pass), we can now run &lt;code&gt;mix credo&lt;/code&gt; on our project. However, even
though we know the code is using a &amp;quot;bare import&amp;quot;, Credo is still not reporting the issue! To fix that, we need to add our
custom check to the Credo config first. In this project, we don&amp;#39;t have the config file yet: we have to create it
with &lt;code&gt;mix credo gen.config&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This will create quite a big &lt;code&gt;.credo.exs&lt;/code&gt; file with the default configuration. We can skip most of it. Just find a &lt;code&gt;requires&lt;/code&gt;
key and add the path to our check there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;requires: [&amp;quot;lib/credo/precise_imports.ex&amp;quot;],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we need to add the check to the &lt;code&gt;enabled&lt;/code&gt; section:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;checks: %{
  enabled: [
    {Credo.Check.Readability.PreciseImports, []},
    [...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, we can now run &lt;code&gt;mix credo&lt;/code&gt; again.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ mix credo
Checking 1 source file ...

  Code Readability
┃
┃ [R] → Use :only with import statements
┃       lib/my_app.ex:3 #(MyApp)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we change it to use &lt;code&gt;only&lt;/code&gt;, the check will pass. If we change it to use &lt;code&gt;except&lt;/code&gt;, but not &lt;code&gt;only&lt;/code&gt;, the check will fail
again (we should probably add a test for this).&lt;/p&gt;
&lt;h3&gt;Improving Our Explanation for Credo&lt;/h3&gt;
&lt;p&gt;One last thing we should do is to improve the explanation we passed as an option to &lt;code&gt;use Credo.Check&lt;/code&gt;. Change it to
something more descriptive:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Credo.Check.Readability.PreciseImports do
  @moduledoc false
  use Credo.Check,
    base_priority: :normal,
    explanations: [
      check: &amp;quot;&amp;quot;&amp;quot;
      Using bare import statements, without specifying what we are
      importing makes it hard to reason about from where the function
      comes from...
      &amp;quot;&amp;quot;&amp;quot;
    ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now it will look better when we run &lt;code&gt;mix credo explain&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ mix credo explain lib/my_app.ex:3

  MyApp
┃
┃   [R] Category: readability
┃    →  Priority: normal
┃
┃       Use :only with import statements
┃       lib/my_app.ex:3 (MyApp)
┃
┃    __ CODE IN QUESTION
┃
┃     1 defmodule MyApp do
┃     2   @moduledoc false
┃     3   import MyApp.Helpers, except: [hello: 0]
┃     4 end
┃     5
┃
┃    __ WHY IT MATTERS
┃
┃       Using bare import statements, without specifying what we are
┃       importing makes it hard to reason about from where the function
┃       comes from...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we learned how to create a Credo check to enforce a custom code rule. We discussed using tokenization and
AST generation to match bad code. Finally, we ran some tests and enabled the Credo check in Elixir.&lt;/p&gt;
&lt;p&gt;Happy static analyzing!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Deep Dive into Subscriptions with Absinthe</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/08/08/a-deep-dive-into-subscriptions-with-absinthe.html"/>
    <id>https://blog.appsignal.com/2023/08/08/a-deep-dive-into-subscriptions-with-absinthe.html</id>
    <published>2023-08-08T00:00:00+00:00</published>
    <updated>2023-08-08T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the final part of this series, we&#039;ll see how GraphQL subscriptions work and how to create them with Absinthe.</summary>
    <content type="html">&lt;p&gt;In this series, we&amp;#39;ve seen how to create GraphQL APIs in Elixir using Absinthe.
So far, we have only discussed a one-way communication channel where the client makes the queries or mutations, and the server responds.&lt;/p&gt;
&lt;p&gt;GraphQL also supports a long-running subscription between the client and the server where the server can notify the client of events.
This can be very useful in multi-user scenarios where many users might interact with the same resource at the same time.
For example, in a blogging application, the client can subscribe to the server to receive new comments as they are posted instead of having to poll the server for them.&lt;/p&gt;
&lt;p&gt;This is now a two-way communication and the regular HTTP transport is not well suited for it. Let’s see how subscriptions work and how to create them.&lt;/p&gt;
&lt;h2&gt;Creating Subscriptions in Absinthe for Elixir&lt;/h2&gt;
&lt;p&gt;Creating subscriptions is very similar to creating query or mutation fields.
We just need to create a &lt;code&gt;field&lt;/code&gt; inside the &lt;code&gt;subscription do ... end&lt;/code&gt; block of our schema.&lt;/p&gt;
&lt;p&gt;Let’s create a subscription for observing new comments inside the schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app_web/schema.ex

defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  # ...

  subscription do
    field :comment_added, :comment do
      arg :post_id, non_null(:id)

      config fn %{post_id: id}, %{context: context} -&amp;gt;
        {:ok, topic: &amp;quot;post:#{id}&amp;quot;}
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s break this down.
We add a field named &lt;code&gt;comment_added&lt;/code&gt; inside the subscription block.
The return type of this field is &lt;code&gt;comment&lt;/code&gt; (defined using the &lt;code&gt;object&lt;/code&gt; macro in Absinthe — see &lt;a href=&quot;https://blog.appsignal.com/2023/05/16/an-introduction-to-absinthe-for-elixir.html&quot;&gt;An Introduction to Absinthe&lt;/a&gt; for details).
This field accepts an argument named &lt;code&gt;post_id&lt;/code&gt; which is required.
So far, everything is similar to what we would do when creating a field in a &lt;code&gt;query&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#config/1&quot;&gt;&lt;code&gt;config&lt;/code&gt;&lt;/a&gt; macro is what is new here and it is used to configure the subscription field.
This is also where we can perform other checks like authorization to accept/reject the subscription.
The function passed to config receives the arguments passed to the field and the &lt;code&gt;Absinthe.Resolution&lt;/code&gt; struct that contains information like context.
The return value can be an &lt;code&gt;{:ok, topic: topic}&lt;/code&gt; tuple for success or &lt;code&gt;{:error, reason}&lt;/code&gt; tuple.
The &lt;code&gt;topic&lt;/code&gt; is what Absinthe uses to identify subscribers who should be notified of an event.
We will get to it in a few minutes.
But just for completeness, the &lt;code&gt;topic&lt;/code&gt; can be a single string or a list containing multiple topics to subscribe to.&lt;/p&gt;
&lt;h2&gt;Publishing Data to Subscriptions in GraphQL&lt;/h2&gt;
&lt;p&gt;We have a subscription added to our schema.
But even after subscribing, we won’t get back any data because we haven’t triggered any updates yet.&lt;/p&gt;
&lt;h3&gt;Trigger from Mutations&lt;/h3&gt;
&lt;p&gt;The easiest way to trigger the subscription is to use the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#trigger/2&quot;&gt;&lt;code&gt;trigger/2&lt;/code&gt;&lt;/a&gt; macro inside the subscription field.
It accepts the name of a &lt;code&gt;mutation&lt;/code&gt; to trigger the subscription and a &lt;code&gt;topic&lt;/code&gt; function.
Assuming that we have a mutation named &lt;code&gt;create_comment&lt;/code&gt; in our schema to create a comment, let’s update our subscription to trigger every time a comment is created.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

    # ...

  subscription do
    field :comment_added, :comment do
            # arg and config ...

      trigger :create_comment, topic: fn comment -&amp;gt;
        &amp;quot;post:#{comment.post_id}&amp;quot;
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function we pass as &lt;code&gt;topic&lt;/code&gt; to &lt;code&gt;trigger&lt;/code&gt; will be executed with the &lt;code&gt;create_comment&lt;/code&gt; mutation result.
It should return the name of the topic that this mutation will trigger.&lt;/p&gt;
&lt;p&gt;Let’s see this in action.
First, user A runs a subscription query like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;subscription {
  commentAdded(postId: 1) {
    id
    body
    author {
      id
      name
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Absinthe records the subscription, but the user doesn’t receive any data straight away.&lt;/p&gt;
&lt;p&gt;Now, user B creates a new comment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;mutation {
  createComment(comment: { postId: 1, body: &amp;quot;nice post!&amp;quot; }) {
    id
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;User B will receive the mutation response as usual based on the selections:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;data&amp;quot;: {
    &amp;quot;createComment&amp;quot;: {
      &amp;quot;id&amp;quot;: 1
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, user A will also receive a response on their subscription.
Since they selected many more fields when subscribing, the response will include them all regardless of the selections in the mutation.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;data&amp;quot;: {
    &amp;quot;commentAdded&amp;quot;: {
      &amp;quot;id&amp;quot;: 1,
      &amp;quot;body&amp;quot;: &amp;quot;nice post!&amp;quot;,
      &amp;quot;author&amp;quot;: {
        &amp;quot;id&amp;quot;: 1,
        &amp;quot;name&amp;quot;: &amp;quot;User B&amp;quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that with the current setup, user B won&amp;#39;t actually receive any updates yet since the subscription wasn&amp;#39;t made using a WebSocket transport.
We will see how to set that up later in this post.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Translate Mutation Result to Subscription Result&lt;/h3&gt;
&lt;p&gt;If your mutation returns a different data structure from what the subscription is supposed to return, it is also possible to use a &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#resolve/1&quot;&gt;&lt;code&gt;resolve&lt;/code&gt;&lt;/a&gt; inside the subscription to convert the result first.&lt;/p&gt;
&lt;p&gt;For example, assume that instead of returning a &lt;code&gt;comment&lt;/code&gt;, the &lt;code&gt;create_comment&lt;/code&gt; mutation returns a complex object that also includes validation errors in case of failure.
In that case, we can provide a resolver for the &lt;code&gt;comment_added&lt;/code&gt; subscription field to fetch the comment before returning the result.
We will also need to modify our trigger to create the topic from the response struct.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  object :comment_mutation_result do
    field :comment, :comment
    field :errors, list_of(:string)
  end

  mutation do
    field :create_comment, :comment_mutation_result do
      arg :comment, non_null(:comment_create_input)

      resolve fn %{comment: attrs}, _resolution -&amp;gt;
        case MyAppWeb.Blog.create_comment(attrs) do
          {:ok, comment} -&amp;gt;
            {:ok, %{comment: comment, errors: []}}
          {:error, changeset} -&amp;gt;
            {:ok, %{comment: nil, errors: translate_changeset_errors(changeset)}}
        end
      end
    end
  end

  subscription do
    field :comment_added, :comment do
      arg :post_id, non_null(:id)

      config fn %{post_id: id} = args, %{context: context} -&amp;gt;
        {:ok, topic: &amp;quot;post:#{id}&amp;quot;}
      end

      trigger :create_comment, topic: fn
        %{comment: nil} -&amp;gt; []
        %{comment: comment} -&amp;gt; &amp;quot;post:#{comment.post_id}&amp;quot;
      end

      resolve fn %{comment: comment}, _args, _resolution -&amp;gt;
        {:ok, comment}
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Trigger from Application Code&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;trigger&lt;/code&gt; macro works great as long as the only way to create a comment is through the GraphQL API.
But that might not always be the case.
For example, you might have a separate REST API or traditional Phoenix-based controllers/Live Views that create those comments.
In that case, it is usually better to drop the &lt;code&gt;trigger&lt;/code&gt; from the GraphQL API and publish notifications at a lower level from the application code.&lt;/p&gt;
&lt;p&gt;This can be achieved using the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Subscription.html#publish/3&quot;&gt;&lt;code&gt;Absinthe.Subscription.publish/3&lt;/code&gt;&lt;/a&gt; method.
A good place to put this might be inside the Phoenix Context method that creates the comment.
Let’s do that now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Blog do
  # ...

  def create_comment(attrs) do
    %Comment{}
    |&amp;gt; Comment.changeset(attrs)
    |&amp;gt; Repo.insert()
    |&amp;gt; tap(fn
      {:ok, comment} -&amp;gt;
        Absinthe.Subscription.publish(MyAppWeb.Endpoint, comment, comment_created: &amp;quot;post:#{comment.post_id}&amp;quot;)
      _ -&amp;gt;
        nil
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The name of the subscription field to trigger (&lt;code&gt;comment_updated&lt;/code&gt;) is passed as a key inside the last argument to this function.
The value of that key is the &lt;code&gt;topic&lt;/code&gt; to target.&lt;/p&gt;
&lt;p&gt;Note that you use both the &lt;code&gt;trigger&lt;/code&gt; macro and &lt;code&gt;publish/3&lt;/code&gt;.
Just make sure that the code that calls &lt;code&gt;publish&lt;/code&gt; is not being executed from the mutation referenced in the &lt;code&gt;trigger&lt;/code&gt;. Otherwise, the user will receive two messages for a single comment — one from the &lt;code&gt;trigger&lt;/code&gt; macro and another from &lt;code&gt;publish&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Server-Side Setup with Phoenix PubSub&lt;/h2&gt;
&lt;p&gt;At the beginning of the post, we discussed that a simple one-way HTTP transport is not well-suited for subscriptions.
Let&amp;#39;s come back to that topic and see how we can set up the application to support a long-running two-way connection between the application and the client.&lt;/p&gt;
&lt;p&gt;The easiest way to do it is using Phoenix PubSub which is present by default in all Phoenix applications.
Let’s install Absinthe’s Phoenix helpers by adding the following dependency in &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:absinthe_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, configure the &lt;code&gt;PubSub&lt;/code&gt; and add it to the supervision tree (this might already be configured for you if you generated the application using &lt;code&gt;phx.new&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/config.exs
config :my_app, MyAppWeb.Endpoint, pubsub_server: MyApp.PubSub

# lib/my_app/application.ex
defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      # ...
      # Start the PubSub system
      {Phoenix.PubSub, name: MyApp.PubSub},
      # Absinthe Subscription
      {Absinthe.Subscription, MyAppWeb.Endpoint},
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we also added &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Subscription.html&quot;&gt;&lt;code&gt;Absinthe.Subscription&lt;/code&gt;&lt;/a&gt; inside the supervision tree which keeps track of all the active subscriptions and takes care of delivering notifications to the subscribed clients.
We pass the name of the endpoint as the only argument, but other configuration options are available — see &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Subscription.html#child_spec/1&quot;&gt;&lt;code&gt;Absinthe.Subscription.child_spec/1&lt;/code&gt;&lt;/a&gt; for full details.&lt;/p&gt;
&lt;p&gt;Next, use &lt;code&gt;Absinthe.Phoenix.Endpoint&lt;/code&gt; inside your web application’s endpoint module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app_web/endpoint.ex
defmodule MyAppWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :my_app
  use Absinthe.Phoenix.Endpoint

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It adds some utility methods to the Endpoint module used by &lt;code&gt;Absinthe.Subscription&lt;/code&gt; to publish the results of the subscription.&lt;/p&gt;
&lt;p&gt;Finally, use &lt;code&gt;Absinthe.Phoenix.Socket&lt;/code&gt; inside the socket module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/spendra_web/channels/user_socket.ex
defmodule MyAppWeb.UserSocket do
  use Phoenix.Socket
  use Absinthe.Phoenix.Socket, schema: MyAppWeb.Schema

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This adds a special &lt;a href=&quot;https://hexdocs.pm/phoenix/channels.html&quot;&gt;channel&lt;/a&gt; to the socket - &lt;a href=&quot;https://github.com/absinthe-graphql/absinthe_phoenix/blob/master/lib/absinthe/phoenix/channel.ex&quot;&gt;&lt;code&gt;Absinthe.Phoenix.Channel&lt;/code&gt;&lt;/a&gt; - that handles communication with the &lt;code&gt;Absinthe.Subscription&lt;/code&gt; server we added to our supervision tree.&lt;/p&gt;
&lt;p&gt;I know this is a lot to take in, but Absinthe does a really good job of managing everything internally. We only need the few lines of code we see above for everything to work on the server side.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://blog.appsignal.com/2023/07/04/a-deep-dive-into-mutations-with-absinthe.html#an-example-using-absinthe-context&quot;&gt;previous post of this series&lt;/a&gt;, we saw that we could add a &lt;a href=&quot;https://hexdocs.pm/absinthe/context-and-authentication.html&quot;&gt;context&lt;/a&gt; available to all our queries and mutations.
Since the new requests for subscriptions are now going through the &lt;code&gt;UserSocket&lt;/code&gt; instead of the regular&lt;code&gt;:graphql&lt;/code&gt; pipeline in the schema, we don&amp;#39;t have access to the context inside the subscriptions.
To get it back, we need to put it inside the socket during the &lt;code&gt;connect&lt;/code&gt; callback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.UserSocket do
  use Phoenix.Socket
  use Absinthe.Phoenix.Socket, schema: MyAppWeb.Schema

  # ...

  @impl true
  def connect(query_params, socket, _connect_info) do
    case authorize_user(socket, query_params) do
      {:ok, user} -&amp;gt;
        {:ok, Absinthe.Phoenix.Socket.put_options(socket, context: %{current_user: user})}
      {:error, _reason} -&amp;gt;
        # Reject the connection
        :error
    end
  end

  defp authorize_user(socket, query_params) do
    # Fetch the user here (for example, from a token in the query_params)
    {:ok, user}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Client-Side Setup with Apollo&lt;/h2&gt;
&lt;p&gt;Now that our server is ready to accept connections over WebSocket, let’s set up the client.
Since &lt;a href=&quot;https://www.apollographql.com/docs/react/&quot;&gt;Apollo&lt;/a&gt; is usually the go-to client for client-side GQL usage, I will only cover that in this post.
If you are using Relay, check out &lt;a href=&quot;https://hexdocs.pm/absinthe/relay.html&quot;&gt;Using Absinthe with Relay&lt;/a&gt;.
For usage without external clients, check out the &lt;a href=&quot;https://github.com/absinthe-graphql/absinthe-socket/tree/master/packages/socket&quot;&gt;&lt;code&gt;@absinthe/socket&lt;/code&gt;&lt;/a&gt; package, which provides a way to send subscription requests and observe the results.&lt;/p&gt;
&lt;p&gt;If you are new to Apollo, I suggest going through the &lt;a href=&quot;https://www.apollographql.com/docs/react/&quot;&gt;Introduction to Apollo Client docs&lt;/a&gt; before going further because we will use advanced concepts to customize our client.&lt;/p&gt;
&lt;p&gt;In a regular setup, Apollo is usually configured to use an &lt;a href=&quot;https://www.apollographql.com/docs/react/api/link/apollo-link-http/&quot;&gt;HTTP Link&lt;/a&gt; that, by default, sends a &lt;code&gt;POST&lt;/code&gt; request to the endpoint whenever a new query/mutation is executed.
We now want to modify it to send the request over a WebSocket connection instead of a regular HTTP request.&lt;/p&gt;
&lt;p&gt;First, let’s create a standard Phoenix WebSocket connection:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// assets/js/app.js
import { Socket as PhoenixSocket } from &amp;quot;phoenix&amp;quot;;

const phoenixSocket = new PhoenixSocket(&amp;quot;ws://localhost:4000/socket&amp;quot;, {
  params: () =&amp;gt; {
    const token = &amp;quot;xxx&amp;quot;; // an auth token (e.g. from cookies or another authentication process)
    return { token };
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can pass any hash as &lt;code&gt;params&lt;/code&gt; when opening the socket connection.
The above is just an example where we send a &lt;code&gt;token&lt;/code&gt; that can then be used inside &lt;code&gt;MyAppWeb.UserSocket.connect/3&lt;/code&gt; above to authorize a user.&lt;/p&gt;
&lt;p&gt;Next, wrap it inside an &lt;code&gt;AbsintheSocket&lt;/code&gt; and create a link for use with the Apollo client:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import * as AbsintheSocket from &amp;quot;@absinthe/socket&amp;quot;;
import { createAbsintheSocketLink } from &amp;quot;@absinthe/socket-apollo-link&amp;quot;;

const absintheSocket = AbsintheSocket.create(phoenixSocket);
const websocketLink = createAbsintheSocketLink(absintheSocket);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that you will need to install &lt;code&gt;@absinthe/socket&lt;/code&gt; and &lt;code&gt;@absinthe/socket-apollo-link&lt;/code&gt; with &lt;code&gt;npm&lt;/code&gt;/&lt;code&gt;yarn&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, we will set up the Apollo client to use this link:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { ApolloClient, InMemoryCache } from &amp;quot;@apollo/client&amp;quot;;

const client = new ApolloClient({
  link: websocketLink,
  cache: new InMemoryCache(),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this approach works for all types of documents (queries, mutations, or subscriptions), it sends all of them over the WebSocket.
It is usually better to send regular POST requests to the API endpoint in your application for regular queries and mutations and only use WebSocket when creating subscriptions.&lt;/p&gt;
&lt;p&gt;This is possible using the &lt;a href=&quot;https://www.apollographql.com/docs/react/api/link/introduction/#directional&quot;&gt;Apollo client’s &lt;code&gt;split&lt;/code&gt; function&lt;/a&gt; to choose which &lt;code&gt;ApolloLink&lt;/code&gt; to use for each request.
Let’s set it up to only use the &lt;code&gt;websocketLink&lt;/code&gt; for subscriptions and create an &lt;code&gt;HttpLink&lt;/code&gt; for other operations:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;import { Socket as PhoenixSocket } from &amp;quot;phoenix&amp;quot;;
import * as AbsintheSocket from &amp;quot;@absinthe/socket&amp;quot;;
import { createAbsintheSocketLink } from &amp;quot;@absinthe/socket-apollo-link&amp;quot;;
import { ApolloClient, HttpLink, InMemoryCache, split } from &amp;quot;@apollo/client&amp;quot;;
import { hasSubscription } from &amp;quot;@jumpn/utils-graphql&amp;quot;;

// Create the websocket link
const phoenixSocket = new PhoenixSocket(&amp;quot;ws://localhost:4000/socket&amp;quot;, {
  params: () =&amp;gt; {
    const token = &amp;quot;xxx&amp;quot;; // an auth token (e.g. from cookies or another authentication process)
    return { token };
  },
});
const absintheSocket = AbsintheSocket.create(phoenixSocket);
const websocketLink = createAbsintheSocketLink(absintheSocket);

// Create http link
const httpLink = new HttpLink({ uri: &amp;quot;http://localhost:4000/api&amp;quot; });

// Create a split link
const link = split(
  (operation) =&amp;gt; hasSubscription(operation.query),
  websocketLink,
  httpLink,
);

// Create the client
const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we are using the &lt;code&gt;hasSubscription&lt;/code&gt; helper method from &lt;code&gt;@jumpn/utils-graphql&lt;/code&gt; to check if a query has a subscription. If so, we route it to the &lt;code&gt;websocketLink&lt;/code&gt; and all other queries to &lt;code&gt;httpLink&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, with this setup, you can start using &lt;a href=&quot;https://www.apollographql.com/docs/react/data/subscriptions/&quot;&gt;&lt;code&gt;useSubscription&lt;/code&gt;&lt;/a&gt; inside your react component or &lt;a href=&quot;https://www.apollographql.com/docs/react/api/core/ApolloClient/#subscribe&quot;&gt;&lt;code&gt;client.subscribe&lt;/code&gt;&lt;/a&gt; outside React components to subscribe for updates. Let&amp;#39;s see how to create a React component that shows new comments as they are posted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;// assets/js/components/NewComments.jsx

import { gql, useSubscription } from &amp;quot;@apollo/client&amp;quot;;
import { useState } from &amp;quot;react&amp;quot;;

const COMMENTS_SUBSCRIPTION = gql`
  subscription ($postId: ID!) {
    commentAdded(postId: $postId) {
      id
      body
    }
  }
`;

export default function NewComments({ postId }) {
  const [comments, setComments] = useState([]);

  useSubscription(COMMENTS_SUBSCRIPTION, {
    variables: { postId },
    onData: ({ commentAdded }) =&amp;gt; {
      setComments((existing) =&amp;gt; [...existing, commentAdded]);
    },
  });

  return (
    &amp;lt;div&amp;gt;
      {comments.map((comment) =&amp;gt; (
        &amp;lt;div key={comment.id}&amp;gt;{comment.body}&amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;GraphQL subscriptions provide a great way to add real-time behavior to your app.
In this post, we saw how to set up the server and the client to support subscriptions.&lt;/p&gt;
&lt;p&gt;Since plain HTTP isn’t well suited for long-running connections with two-way server communication, we also saw how to allow Absinthe on the server and Apollo client to communicate over WebSockets for subscriptions.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Add a Form to a Modal in Phoenix 1.7</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/08/01/add-a-form-to-a-modal-in-phoenix-1-7.html"/>
    <id>https://blog.appsignal.com/2023/08/01/add-a-form-to-a-modal-in-phoenix-1-7.html</id>
    <published>2023-08-01T00:00:00+00:00</published>
    <updated>2023-08-01T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In part two of our series, we&#039;ll add a form to the modal we&#039;ve created.</summary>
    <content type="html">&lt;p&gt;In part one of this series, we introduced the core generated components when bootstrapping a new
Phoenix project. We used a button and a modal from the core components to lay the groundwork for
a &amp;quot;create modal&amp;quot;.&lt;/p&gt;
&lt;p&gt;In this post, we will put a form onto the modal and create pets.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: As in the last post, you can follow along with our &lt;a href=&quot;https://github.com/Adzz/petacular&quot;&gt;companion repo&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Adding a Form to Our Phoenix Application&lt;/h2&gt;
&lt;p&gt;There is a &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L186&quot;&gt;simple form&lt;/a&gt; included in &lt;code&gt;PetacularWeb.CoreComponents&lt;/code&gt;. This expects two slots: an &lt;code&gt;:inner_block&lt;/code&gt;, which will be our form input components, and &lt;code&gt;:actions&lt;/code&gt;, which will be the submit buttons.
The &lt;code&gt;:actions&lt;/code&gt; slot is a named slot, meaning, we can render
the components we want to use as buttons inside of an &lt;code&gt;&amp;lt;:actions&amp;gt;&lt;/code&gt; tag, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in /lib/petacular_web/pages/home_live.ex

&amp;lt;PetacularWeb.CoreComponents.simple_form for={@create_form} phx-submit=&amp;quot;create_pet&amp;quot;&amp;gt;
  &amp;lt;:actions&amp;gt;
    &amp;lt;PetacularWeb.CoreComponents.button&amp;gt;
      Save
    &amp;lt;/PetacularWeb.CoreComponents.button&amp;gt;
  &amp;lt;/:actions&amp;gt;
&amp;lt;/PetacularWeb.CoreComponents.simple_form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L266&quot;&gt;input components are also in &lt;code&gt;PetacularWeb.CoreComponents&lt;/code&gt;&lt;/a&gt; and produce the correct kind of input based on the &lt;code&gt;attrs&lt;/code&gt;
used to define them. We just need a text field for now, so we can define the text input like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;PetacularWeb.CoreComponents.input field={@create_form[:name]} label=&amp;quot;Name&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don&amp;#39;t define a &lt;code&gt;type&lt;/code&gt; attr, it defaults to a text field. The &lt;code&gt;@create_form&lt;/code&gt; is created from
a changeset (as we will see in a moment).&lt;/p&gt;
&lt;h3&gt;Phoenix&amp;#39;s Component &lt;code&gt;to_form&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s take a moment to talk about forms and changesets. We used to pass changesets directly
to forms. But in Phoenix 1.7, a new &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#to_form/2&quot;&gt;&lt;code&gt;to_form&lt;/code&gt;&lt;/a&gt;
function generates a &lt;a href=&quot;https://hexdocs.pm/phoenix_html/Phoenix.HTML.Form.html&quot;&gt;&lt;code&gt;Phoenix.HTML.Form&lt;/code&gt;&lt;/a&gt;
struct from the given changeset.&lt;/p&gt;
&lt;p&gt;This seemingly small change is a massive improvement, so it&amp;#39;s worth talking about. First, it
provides us with some indirection. Calling &lt;code&gt;to_form&lt;/code&gt; ensures that what the &lt;code&gt;&amp;lt;.form&lt;/code&gt; component
sees is a &lt;code&gt;Phoenix.HTML.Form&lt;/code&gt; struct, rather than a changeset. That means if we wanted to swap away from a changeset and use something else in the future (like a bare
map of params), we could — with no changes to the &lt;code&gt;&amp;lt;.form&lt;/code&gt; component itself. We just change
the places we call &lt;code&gt;to_form&lt;/code&gt; in &lt;code&gt;mount&lt;/code&gt; and &lt;code&gt;handle_event&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, the &lt;code&gt;Phoenix.HTML.Form&lt;/code&gt; handles change tracking better. Up until Phoenix 1.7, if a form field
changed, the whole form was re-rendered. Usually that&amp;#39;s fine, but if you have a large complex
form or dropdowns with lots of options, it can be a big boon not to have to
re-render all of that each time you change a field.&lt;/p&gt;
&lt;p&gt;Finally, it also simplifies the syntax. When we passed changesets through to forms, we used the &lt;code&gt;:let&lt;/code&gt; attribute to assign the changeset to a variable we could refer to. Now
we can omit that entirely. We can also refer to the value of a form field more simply; previously,
you would have done something like: &lt;code&gt;value={Ecto.Changeset.fetch_field!(@changeset, :my_field)}&lt;/code&gt;.
With the form struct, it becomes: &lt;code&gt;value={@form[:my_field].value}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A full before and after might look like this.&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@impl true
def mount(_params, _session, socket) do
  default_assigns = %{
    changeset: Petacular.Pet.create_changeset(%{})
  }

  {:ok, assign(socket, default_assigns)}
end

~H&amp;quot;&amp;quot;&amp;quot;
&amp;lt;.form :let={f} for={@changeset} phx-submit=&amp;quot;...&amp;quot;&amp;gt;
  &amp;lt;%= &amp;lt;Phoenix.HTML.Form.text_input(f, :my_field, value: Ecto.Changeset.fetch_field!(@changeset, :my_field)) %&amp;gt;
&amp;lt;/.form&amp;gt;
&amp;quot;&amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And after:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@impl true
def mount(_params, _session, socket) do
  default_assigns = %{
    create_form: Phoenix.Component.to_form(Petacular.Pet.create_changeset(%{}))
  }

  {:ok, assign(socket, default_assigns)}
end

~H&amp;quot;&amp;quot;&amp;quot;
&amp;lt;.form for={@create_form} phx-submit=&amp;quot;...&amp;quot;&amp;gt;
  &amp;lt;input type=&amp;quot;text&amp;quot; name={@create_form[:my_field]} value={@create_form[:my_field].value} /&amp;gt;
&amp;lt;/.form&amp;gt;
&amp;quot;&amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note how we don&amp;#39;t need &lt;code&gt;HTML.text_input&lt;/code&gt; anymore, and we don&amp;#39;t have to reach into the changeset.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#form/1-using-the-for-attribute&quot;&gt;Check out the official Phoenix docs for more information&lt;/a&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Using &lt;code&gt;to_form&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;First, set up a form in &lt;code&gt;mount&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@impl true
def mount(_params, _session, socket) do
  default_assigns = %{
    create_form: Phoenix.Component.to_form(Petacular.Pet.create_changeset(%{}))
  }

  {:ok, assign(socket, default_assigns)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can build a form and use the pre-built inputs. These accept the field from the form
(which is as easy as &lt;code&gt;field={@create_form[:name]}&lt;/code&gt;).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;PetacularWeb.CoreComponents.modal id=&amp;quot;create_modal&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Add a pet.&amp;lt;/h2&amp;gt;

  &amp;lt;PetacularWeb.CoreComponents.simple_form
    for={@create_form}
    phx-submit=&amp;quot;create_pet&amp;quot;
  &amp;gt;
    &amp;lt;PetacularWeb.CoreComponents.input field={@create_form[:name]} label=&amp;quot;Name&amp;quot; /&amp;gt;
    &amp;lt;:actions&amp;gt;
      &amp;lt;PetacularWeb.CoreComponents.button&amp;gt;
        Save
      &amp;lt;/PetacularWeb.CoreComponents.button&amp;gt;
    &amp;lt;/:actions&amp;gt;
  &amp;lt;/PetacularWeb.CoreComponents.simple_form&amp;gt;
&amp;lt;/PetacularWeb.CoreComponents.modal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Saving the Form&lt;/h3&gt;
&lt;p&gt;If we save and refresh the form, we should see that we can click a button and enter a name into it.
The final thing to do to get this working is to write an event handler for the form submission.&lt;/p&gt;
&lt;p&gt;Here is the first gotcha. We are using changesets to validate our forms. Because live views
are stateful, we might be tempted to re-use the changeset in our assigns when we submit the
form. This is not a good idea. What&amp;#39;s worse, &lt;code&gt;Ecto.Changeset.cast&lt;/code&gt; et al. will happily accept
a changeset as input, meaning it&amp;#39;s a very easy trap to fall into without realizing you are
doing something wrong. The symptom might be errors in your changeset not
disappearing as you expect, for example.&lt;/p&gt;
&lt;p&gt;This trap is harder to fall into if you use &lt;code&gt;to_form&lt;/code&gt; because the changeset is not in
the assigns — the form struct is. This is another good reason to use &lt;code&gt;to_form&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;So every time we want to cast some params, we must create a fresh changeset. Let&amp;#39;s do that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex
@impl true
def handle_event(&amp;quot;create_pet&amp;quot;, %{&amp;quot;pet&amp;quot; =&amp;gt; params}, socket) do
  case Repo.insert(Petaclular.Pet.create_changeset(params)) do
    {:error, message} -&amp;gt;
      {:noreply, socket |&amp;gt; put_flash(:error, inspect(message))}

    {:ok, _} -&amp;gt;
      new_assigns = %{}
      {:noreply, assign(socket, new_assigns)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the case of an error, we add a flash that shows it to the user, and when we
successfully complete, we need to do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Show the created pet.&lt;/li&gt;
&lt;li&gt;Close the modal.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To show the new pet, we first need to render all pets on the page. So we will
fetch them all from the DB in mount and then add some code to render them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex
@impl true
def mount(_params, _session, socket) do
  default_assigns = %{
    pets: Repo.all(Petacular.Pet),
    create_form: Phoenix.Component.to_form(Petacular.Pet.create_changeset(%{}))
  }

  {:ok, assign(socket, default_assigns)}
end

...

&amp;lt;h1 class=&amp;quot;font-semibold text-3xl mb-4&amp;quot;&amp;gt;Pets&amp;lt;/h1&amp;gt;

&amp;lt;div class=&amp;quot;w-50 mb-4&amp;quot;&amp;gt;
  &amp;lt;%= for pet &amp;lt;- @pets do %&amp;gt;
    &amp;lt;p&amp;gt;Name: &amp;lt;span class=&amp;quot;font-semibold&amp;quot;&amp;gt;&amp;lt;%= pet.name %&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we can see them, we can refresh the list of pets when we add one successfully:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex
@impl true
def handle_event(&amp;quot;create_pet&amp;quot;, %{&amp;quot;pet&amp;quot; =&amp;gt; params}, socket) do
  case Repo.insert(Petacular.Pet.create_changeset(params)) do
    {:error, message} -&amp;gt;
      {:noreply, socket |&amp;gt; put_flash(:error, inspect(message))}

    {:ok, _} -&amp;gt;
      new_assigns = %{
        pets: Repo.all(Petacular.Pet)
      #  ^^^ add new
      }

      {:noreply, assign(socket, new_assigns)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is great. If we try adding a pet, we will see the pet gets created and appears on the
page, but the modal remains open.&lt;/p&gt;
&lt;h3&gt;Closing the Modal with &lt;code&gt;push_event&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Once we have successfully added a pet, we want to close
the modal. There is already a &amp;quot;close the modal&amp;quot; button on the modal; the little &lt;code&gt;X&lt;/code&gt; in
the top right-hand corner. What if we could just target that?&lt;/p&gt;
&lt;p&gt;Well, we can! There is a function called &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#push_event/3&quot;&gt;&lt;code&gt;push_event&lt;/code&gt;&lt;/a&gt;
that lets us emit a JS event from the backend. We can add some JavaScript that listens for
that event and triggers a &amp;quot;click&amp;quot; event for the close button, effectively closing the modal.&lt;/p&gt;
&lt;p&gt;First, we call &lt;code&gt;push_event&lt;/code&gt; in the event handler:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/pages/home_live.ex
@impl true
def handle_event(&amp;quot;create_pet&amp;quot;, %{&amp;quot;pet&amp;quot; =&amp;gt; params}, socket) do
  case Repo.insert(Petacular.Pet.create_changeset(params)) do
    {:error, message} -&amp;gt;
      {:noreply, socket |&amp;gt; put_flash(:error, inspect(message))}

    {:ok, _} -&amp;gt;
      new_assigns = %{
        pets: Repo.all(Petacular.Pet),
        create_form: Phoenix.Component.to_form(Petacular.Pet.create_changeset(%{}))
        # reset the form back to being empty ^^^
      }

      socket =
        socket
        |&amp;gt; assign(new_assigns)
        |&amp;gt; push_event(&amp;quot;close_modal&amp;quot;, %{to: &amp;quot;#close_modal_btn_create_modal&amp;quot;})
        #  ^^^^ add this
      {:noreply, socket}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now to react to the event, we have two options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add a global event listener for the event.&lt;/li&gt;
&lt;li&gt;Use a hook.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#39;s try the second approach. First, we&amp;#39;ll wire up the hook in &lt;code&gt;app.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const ModalCloser = {
  mounted() {
    this.handleEvent(&amp;quot;close_modal&amp;quot;, () =&amp;gt; {
      this.el.dispatchEvent(new Event(&amp;quot;click&amp;quot;, { bubbles: true }));
    });
  },
};

let liveSocket = new LiveSocket(&amp;quot;/live&amp;quot;, Socket, {
  params: {
    _csrf_token: csrfToken,
  },
  hooks: {
    ModalCloser: ModalCloser,
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s put the hook onto the close modal button in &lt;code&gt;PetacularWeb.CoreComponents&lt;/code&gt; (remember,
anything that has a hook also needs an ID). To help us later cater for multiple modals on one
page, let&amp;#39;s use the required &lt;code&gt;@id&lt;/code&gt; attr as part of the id:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;button
  id={&amp;quot;close_modal_btn_&amp;quot; &amp;lt;&amp;gt; @id}
  phx-hook=&amp;quot;ModalCloser&amp;quot;
  &amp;lt;!-- ^^ Add these ^^ --&amp;gt;
  phx-click={JS.exec(&amp;quot;data-cancel&amp;quot;, to: &amp;quot;##{@id}&amp;quot;)}
  type=&amp;quot;button&amp;quot;
  class=&amp;quot;-m-3 flex-none p-3 opacity-20 hover:opacity-40&amp;quot;
  aria-label={gettext(&amp;quot;close&amp;quot;)}
&amp;gt;
  &amp;lt;.icon name=&amp;quot;hero-x-mark-solid&amp;quot; class=&amp;quot;h-5 w-5&amp;quot; /&amp;gt;
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see all the changes in &lt;a href=&quot;https://github.com/Adzz/petacular/commit/91e8b86e1f518409de39c1d964f978b03723d52a&quot;&gt;this commit&lt;/a&gt;.
Fantastic, we now have a working create modal! 🎉&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In the second part of this series, we successfully added a form to the modal that creates new pets.&lt;/p&gt;
&lt;p&gt;Stay tuned for the third and final part,
where we will edit an existing pet.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Observe Your Phoenix App with Structured Logging</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/07/18/observe-your-phoenix-app-with-structured-logging.html"/>
    <id>https://blog.appsignal.com/2023/07/18/observe-your-phoenix-app-with-structured-logging.html</id>
    <published>2023-07-18T00:00:00+00:00</published>
    <updated>2023-07-18T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s configure a Phoenix LiveView application to use a structured logger and monitor the app with AppSignal.</summary>
    <content type="html">&lt;p&gt;In this post, we&amp;#39;ll configure a Phoenix LiveView application to use a structured logger. We&amp;#39;ll then use AppSignal to correlate log events with other telemetry signals, like exception reports and traces.&lt;/p&gt;
&lt;p&gt;Along the way, you&amp;#39;ll learn about the benefits of structured logging, and you&amp;#39;ll see how to configure a distinct framework and application logger in your Phoenix app.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;What is Structured Logging?&lt;/h2&gt;
&lt;p&gt;Structured logs conform to a specific structure in which an agreed-upon set of key/value pairs describe common log attributes. Without structured logging, you might get a log line that looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;20:34:05.879 request_id=F1ssWNn62XasBTYAAAEj [info] GET /
20:34:05.911 request_id=F1ssWNn62XasBTYAAAEj [info] hello from the page controller
20:34:05.919 request_id=F1ssWNn62XasBTYAAAEj [info] Sent 200 in 39ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few bits of information make up each log statement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a timestamp&lt;/li&gt;
&lt;li&gt;a level (in this case, &lt;code&gt;info&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;a log message&lt;/li&gt;
&lt;li&gt;a bit of metadata (the &lt;code&gt;request_id&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this unstructured format, all the data is included in one string, so it&amp;#39;s difficult to search and analyze log statements based on each data point.&lt;/p&gt;
&lt;p&gt;Structured logging solves this problem for us. It breaks each piece of information into its own key/value pair. Here&amp;#39;s an example of these same log statements structured using the &lt;a href=&quot;https://brandur.org/logfmt&quot;&gt;logfmt&lt;/a&gt; format:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;timestamp=&amp;quot;20:38:15.973 2023-05-01&amp;quot; level=info message=&amp;quot;GET /&amp;quot; request_id=F1sskxS1k-w0jUIAAAKB
timestamp=&amp;quot;20:38:16.013 2023-05-01&amp;quot; level=info message=&amp;quot;hello from the page controller&amp;quot; request_id=F1sskxS1k-w0jUIAAAKB
timestamp=&amp;quot;20:38:16.031 2023-05-01&amp;quot; level=info message=&amp;quot;Sent 200 in 58ms&amp;quot; request_id=F1sskxS1k-w0jUIAAAKB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can search and analyze log statements based on the &lt;code&gt;timestamp&lt;/code&gt;, &lt;code&gt;level&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, and &lt;code&gt;request_id&lt;/code&gt; fields. For example, you could search all log statements with a shared &lt;code&gt;request_id&lt;/code&gt;, filter log lines by their &lt;code&gt;level&lt;/code&gt; key, or search logs within a range of timestamps.&lt;/p&gt;
&lt;p&gt;Now that we can see the benefits of using structured logs, we can configure our Phoenix LiveView application to use the logfmt format in development and production. But first, we&amp;#39;ll take a closer look at how Phoenix apps configure their loggers out of the box.&lt;/p&gt;
&lt;h2&gt;Logger Configuration in Phoenix&lt;/h2&gt;
&lt;p&gt;By default, your Phoenix application will configure its logger to output unstructured logs to the console. Open up your &lt;code&gt;config.exs&lt;/code&gt; file, and you&amp;#39;ll see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console,
  format: &amp;quot;$time $metadata[$level] $message\n&amp;quot;,
  metadata: [:request_id]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means the logger will use the &lt;a href=&quot;https://hexdocs.pm/logger/Logger.Backends.Console.html&quot;&gt;console backend&lt;/a&gt; to print log messages to the console using the specified (unstructured) format. This configuration says that only the &lt;code&gt;request_id&lt;/code&gt; from the default metadata list should be included in each log statement. Elixir&amp;#39;s &lt;code&gt;Logger&lt;/code&gt; adds a certain set of metadata to all log statements, and you can find the full list &lt;a href=&quot;https://hexdocs.pm/logger/1.12/Logger.html#module-metadata&quot;&gt;here&lt;/a&gt;. The &lt;code&gt;request_id&lt;/code&gt; metadata, however, is not added by default with the Elixir &lt;code&gt;Logger&lt;/code&gt;. Instead, it is added by the &lt;a href=&quot;https://hexdocs.pm/plug/Plug.RequestId.html&quot;&gt;&lt;code&gt;Plug.RequestId&lt;/code&gt;&lt;/a&gt; plug that you&amp;#39;ll see added to your application&amp;#39;s &lt;code&gt;endpoint.ex&lt;/code&gt; file like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# endpoint.ex
plug Plug.RequestId
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s take a quick peek at the rest of the default metadata by setting &lt;code&gt;metadata: :all&lt;/code&gt; in &lt;code&gt;config.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console,
  format: &amp;quot;$time $metadata[$level] $message\n&amp;quot;,
  metadata: :all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when we fire up our app and visit the root path, we&amp;#39;ll see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;21:09:24.947 erl_level=info application=phoenix domain=elixir file=lib/phoenix/logger.ex function=phoenix_endpoint_stop/4 line=231 mfa=Phoenix.Logger.phoenix_endpoint_stop/4 module=Phoenix.Logger pid=&amp;lt;0.815.0&amp;gt; request_id=F1suRjwyEp4CjWAAAACi [info] Sent 200 in 2ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s a lot of information! Too much information for our development environment. These logs are so information-dense that they&amp;#39;re difficult to parse with our human eyes. For that reason, you&amp;#39;ll notice that the &lt;code&gt;dev.exs&lt;/code&gt; file overwrites this configuration to simplify it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console,
  format: &amp;quot;$metadata[$level] $message\n&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the timestamp and metadata are excluded entirely, except for the metadata&amp;#39;s &lt;code&gt;$level&lt;/code&gt; data point.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve seen where and how your Phoenix app configures the logger out-of-the-box, let&amp;#39;s configure the logger to emit structured logs that conform to logfmt.&lt;/p&gt;
&lt;h2&gt;Using Logfmt in Phoenix Development&lt;/h2&gt;
&lt;p&gt;First up, we&amp;#39;ll configure our development environment to use the &lt;code&gt;console&lt;/code&gt; logger backend with a logfmt formatter. For this, we need the LogfmtEx dependency added to our application. Open up your &lt;code&gt;mix.exs&lt;/code&gt; file and add it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:logfmt_ex, &amp;quot;~&amp;gt; 0.4&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go ahead and run &lt;code&gt;mix deps.get&lt;/code&gt; to install the new dependency.&lt;/p&gt;
&lt;p&gt;Next up, we&amp;#39;ll configure our application&amp;#39;s console logger to use this formatter. In &lt;code&gt;dev.exs&lt;/code&gt;, add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console, format: {LogfmtEx, :format}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when you start up your application, you should see structured logs like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;timestamp=&amp;quot;21:18:36.828 2023-05-01&amp;quot; level=info message=&amp;quot;Sent 200 in 45ms&amp;quot; request_id=F1suxrg8tRisBTYAAAmh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that we haven&amp;#39;t overwritten the &lt;code&gt;:metadata&lt;/code&gt; key from the console backend config in &lt;code&gt;config.exs&lt;/code&gt;, so we&amp;#39;re still only logging the &lt;code&gt;request_id&lt;/code&gt; data point from the metadata.&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;ve successfully emitted structured logs to the console, but this isn&amp;#39;t good enough for production. To operate a Phoenix application in production, we need to emit our logs to a third-party service that allows us to search, aggregate, and analyze them at scale. This is where AppSignal comes in.&lt;/p&gt;
&lt;p&gt;In the next section, we&amp;#39;ll incorporate the AppSignal logger into our Phoenix application and configure it to use logfmt.&lt;/p&gt;
&lt;h2&gt;Using Logfmt with the AppSignal Logger in Production&lt;/h2&gt;
&lt;p&gt;If you don&amp;#39;t already have AppSignal installed and configured in your application, you can &lt;a href=&quot;https://docs.appsignal.com/elixir/installation/index.html&quot;&gt;follow the instructions here&lt;/a&gt;. Assuming you have an AppSignal account and organization configured, we&amp;#39;re ready to set up the AppSignal logger backend by &lt;a href=&quot;https://docs.appsignal.com/logging/platforms/integrations/elixir.html#configure-logging&quot;&gt;following the steps in AppSignal&amp;#39;s Logging from Elixir docs&lt;/a&gt;. We&amp;#39;ll use the Elixir integration rather than set up a custom source.&lt;/p&gt;
&lt;p&gt;In our &lt;code&gt;runtime.exs&lt;/code&gt; file, we&amp;#39;ll specify the &lt;code&gt;Appsignal.Logger.Backend&lt;/code&gt;, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :backends, [
  {Appsignal.Logger.Backend, [group: &amp;quot;phoenix&amp;quot;, format: &amp;quot;logfmt&amp;quot;]}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, in &lt;code&gt;runtime.exs&lt;/code&gt;, you&amp;#39;ll want to set the application&amp;#39;s log level to &lt;code&gt;:info&lt;/code&gt;, to ensure we send all logs at the info level and below to AppSignal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, level: :info
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will forward our application&amp;#39;s logs to our AppSignal account and group them under the &lt;code&gt;&amp;quot;phoenix&amp;quot;&lt;/code&gt; group designation. It will treat the format of the log statements as logfmt and allow us to search and analyze our logs based on their attributes.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;If you log into your AppSignal account, select your organization, and select &amp;quot;Logging&amp;quot; -&amp;gt; &amp;quot;Application&amp;quot;, you&amp;#39;ll see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/app-signal-log-example.png&quot; alt=&quot;AppSignal log example&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Note that the log line includes the timestamp, hostname, level, and group (in this case, &lt;code&gt;&amp;quot;phoenix&amp;quot;&lt;/code&gt;). Since we&amp;#39;ve specified &lt;code&gt;&amp;quot;logfmt&amp;quot;&lt;/code&gt; for the &lt;code&gt;Appsignal.Logger.Backend&lt;/code&gt;, each of these attributes is indexed and searchable. All we have to do is double-click any of these attributes on the log line itself, and the search filter on the top of the page will update and execute:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/log-search.png&quot; alt=&quot;Log search&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a closer look at one of these log lines now. The &lt;code&gt;&amp;quot;hello from the page controller&amp;quot;&lt;/code&gt; log line is emitted explicitly in application code by the following line added to the &lt;code&gt;PagesController&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# pages_controller.ex
require Logger

def home(conn, _params) do
  Logger.info(&amp;quot;hello from the page controller&amp;quot;)
  render(conn, :home, layout: false)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we click the &lt;code&gt;&amp;quot;+&amp;quot;&lt;/code&gt; icon next to the log line, we see all of the log line&amp;#39;s metadata:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/log-line-expanded.png&quot; alt=&quot;Expanded log line&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can see that the &lt;code&gt;Appsignal.Logger.Backend&lt;/code&gt; emits &lt;em&gt;all&lt;/em&gt; of the default metadata, along with the &lt;code&gt;request_id&lt;/code&gt;. Since we&amp;#39;re using logfmt, each data point is searchable. So, just like we did with the log attributes displayed in the log line itself, we can click on any metadata attributes to get them added to the search. If you click on the &lt;code&gt;request_id_string&lt;/code&gt; attribute, you&amp;#39;ll see the search query update to look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/request-id-search.png&quot; alt=&quot;Request ID Search&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In fact, we can add additional metadata when we emit log lines (using calls to &lt;code&gt;Logger&lt;/code&gt;), like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Logger.info(&amp;quot;hello from the page controller&amp;quot;, %{user_id: conn.assigns.current_user.id})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, the &lt;code&gt;user_id&lt;/code&gt; attribute is displayed in the details of each log line and searchable just like the &lt;code&gt;request_id&lt;/code&gt; metadata.&lt;/p&gt;
&lt;p&gt;So far, we&amp;#39;ve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configured our Phoenix application&amp;#39;s logger to use the &lt;code&gt;Appsignal.Logger.Backend&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Taught that backend to use logfmt.&lt;/li&gt;
&lt;li&gt;Seen logs emitted and consumed into AppSignal, and got a feel for the basic logging search functionality there.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before we continue exploring the AppSignal logging UI and some of its more useful features, we need to address a problem that&amp;#39;s cropped up.&lt;/p&gt;
&lt;h2&gt;Framework Vs. Application Logs&lt;/h2&gt;
&lt;p&gt;Taking another look at the log statements our Phoenix app has emitted to AppSignal so far, we see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;05-01-2023 10:21:04.383[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Access StreamChatWeb.Endpoint at http://localhost:4000
+05-01-2023 10:21:04.363[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Running StreamChatWeb.Endpoint with cowboy 2.9.0 at 127.0.0.1:4000 (http)
+05-01-2023 10:19:02.709[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]GET /asdfads
+05-01-2023 10:18:51.429[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Sent 200 in 4ms
+05-01-2023 10:18:51.426[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]GET /
+05-01-2023 10:18:51.388[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Sent 302 in 252ms
+05-01-2023 10:18:51.137[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]POST /users/log_in
+05-01-2023 10:18:50.201[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]CONNECTED TO Phoenix.LiveView.Socket in 16µs Transport: :websocket Serializer: Phoenix.Socket.V2.JSONSerializer Parameters: %{&amp;quot;_csrf_token&amp;quot; =&amp;gt; &amp;quot;UQshLhEWIzUbAXgLQTE5bFNXRW8LZ00w3xVHuWYmHt1avWPZ4e6-97ut&amp;quot;, &amp;quot;_live_referer&amp;quot; =&amp;gt; &amp;quot;undefined&amp;quot;, &amp;quot;_mounts&amp;quot; =&amp;gt; &amp;quot;0&amp;quot;, &amp;quot;_track_static&amp;quot; =&amp;gt; %{&amp;quot;0&amp;quot; =&amp;gt; &amp;quot;http://localhost:4000/assets/app.css&amp;quot;, &amp;quot;1&amp;quot; =&amp;gt; &amp;quot;http://localhost:4000/assets/app.js&amp;quot;}, &amp;quot;vsn&amp;quot; =&amp;gt; &amp;quot;2.0.0&amp;quot;}
+05-01-2023 10:18:50.130[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Sent 200 in 34ms
+05-01-2023 10:18:50.097[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]GET /users/log_in
+05-01-2023 10:18:48.255[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Sent 200 in 689µs
+05-01-2023 10:18:48.254[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]GET /
05-01-2023 10:18:48.187[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]hello from the page contoller
+05-01-2023 10:18:48.215[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Sent 200 in 10ms
+05-01-2023 10:18:48.206[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]POST /users/log_out
05-01-2023 10:19:25.413[application][ERROR][SOPHIEs-MacBook-Pro-2.local][phoenix]** (RuntimeError) boom! iex:5: (file) (elixir 1.14.2) src/elixir.erl:309: anonymous fn/4 in :elixir.eval_external_handler/1 (stdlib 4.1.1) erl_eval.erl:748: :erl_eval.do_apply/7 (stdlib 4.1.1) erl_eval.erl:987: :erl_eval.try_clauses/10 (elixir 1.14.2) src/elixir.erl:294: :elixir.eval_forms/4 (elixir 1.14.2) lib/module/parallel_checker.ex:107: Module.ParallelChecker.verify/1 (iex 1.14.2) lib/iex/evaluator.ex:329: IEx.Evaluator.eval_and_inspect/3 (iex 1.14.2) lib/iex/evaluator.ex:303: IEx.Evaluator.eval_and_inspect_parsed/3 (iex 1.14.2) lib/iex/evaluator.ex:292: IEx.Evaluator.parse_eval_inspect/3 (iex 1.14.2) lib/iex/evaluator.ex:187: IEx.Evaluator.loop/1 (iex 1.14.2) lib/iex/evaluator.ex:32: IEx.Evaluator.init/4
+05-01-2023 10:18:47.578[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Sent 200 in 7ms
+05-01-2023 10:18:47.572[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]GET /
+05-01-2023 10:18:46.901[application][INFO][SOPHIEs-MacBook-Pro-2.local][phoenix]Sent 200 in 52ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is a lot of noise in here mixed with some useful bits of information. You can see one error log that will very likely be helpful in debugging, as well as one instance of our &lt;code&gt;&amp;quot;hello from the page controller&amp;quot;&lt;/code&gt; log statement. Those two log lines are very hard to detect amidst the many log lines emitted that indicate the server is up, the WebSocket channel is connected, certain web requests are served, and so on.&lt;/p&gt;
&lt;p&gt;These noisy logs are emitted not from our &lt;em&gt;application&lt;/em&gt; code, but from the Phoenix framework itself. They don&amp;#39;t tell us anything interesting, and they are not an essential part of the overall observability picture of our application. Instead, they create noise and contribute to high log volume, making it harder to find and identify the log statements that we intend to emit from application code.&lt;/p&gt;
&lt;p&gt;For this reason, framework logs should be emitted at the &lt;code&gt;FATAL&lt;/code&gt; level. Application logs that are emitted when exceptions are raised or by explicit calls to &lt;code&gt;Logger&lt;/code&gt; should log at the &lt;code&gt;INFO&lt;/code&gt; level. Phoenix doesn&amp;#39;t expose an easy way for us to do that, but we can build our own custom logger backend to solve this problem. Let&amp;#39;s do that now.&lt;/p&gt;
&lt;h2&gt;Build A Custom Logger Backend&lt;/h2&gt;
&lt;p&gt;A logger backend is really nothing more than a GenServer, and must conform to the following API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implement an &lt;code&gt;init/1&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Implement a &lt;code&gt;handle_event/3&lt;/code&gt; function&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s the skeleton for our backend:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/stream_chat/logger/backend.ex
def init({__MODULE__, options}) do
    {:ok, Keyword.merge([group: __MODULE__, format: :plaintext], options)}
  end

  def handle_event(
        {level, _gl, {Logger, message, _timestamp, metadata}},
        options
      ) do
      # ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;init/1&lt;/code&gt; function will be called with whatever config we pass to the call to configure the logger backend in &lt;code&gt;runtime.exs&lt;/code&gt;. It returns the &lt;code&gt;{:ok, state}&lt;/code&gt; tuple.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;handle_event/2&lt;/code&gt; function will be called with all the data we need to emit a log statement with the &lt;code&gt;Appsignal.Logger&lt;/code&gt;, including the:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Level&lt;/li&gt;
&lt;li&gt;Log message&lt;/li&gt;
&lt;li&gt;Metadata&lt;/li&gt;
&lt;li&gt;Internal state of the logger backend process that we established in &lt;code&gt;init/1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whenever the Phoenix framework itself calls the Phoenix application&amp;#39;s logger, the &lt;code&gt;metadata&lt;/code&gt; variable passed to &lt;code&gt;handle_event/2&lt;/code&gt; will include an &lt;code&gt;:application&lt;/code&gt; key pointing to a value of &lt;code&gt;:phoenix&lt;/code&gt;. Where logs are emitted by an explicit call to &lt;code&gt;Logger&lt;/code&gt; or by an exception raised in our application, the &lt;code&gt;metadata&lt;/code&gt; keyword list will &lt;em&gt;not&lt;/em&gt; include an &lt;code&gt;:application&lt;/code&gt; key. We want to be able to write some code that says: &amp;quot;Only log statements coming from Phoenix if they are at the configured log level or below&amp;quot;. We can do exactly that by adding some logic that looks for &lt;code&gt;metadata&lt;/code&gt; with &lt;code&gt;application: :phoenix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Before we write that code, let&amp;#39;s take a look at how we will configure this custom logger backend in our &lt;code&gt;runtime.exs&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :backends, [
  {StreamChat.Logger.Backend,
   [
     format: &amp;quot;logfmt&amp;quot;,
     application_config: [
       phoenix: [
         level_lower_than: :fatal
       ],
       default: [
        level_lower_than: :info
       ]
     ]
   ]}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we include a key &lt;code&gt;:application_config&lt;/code&gt;, which points to another keyword list. That keyword list contains configs for the &lt;code&gt;:phoenix&lt;/code&gt; app along with the &lt;code&gt;:default&lt;/code&gt; app. This data will be passed to the &lt;code&gt;init/1&lt;/code&gt; function and stored in our backend&amp;#39;s state. So, when &lt;code&gt;handle_event/2&lt;/code&gt; is called later on, we can do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check if the &lt;code&gt;metadata&lt;/code&gt; contains &lt;code&gt;application: :phoenix&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If so, check the provided &lt;code&gt;level&lt;/code&gt; and only log if it is at or below the level stored in &lt;code&gt;application_config: [phoenix: [level_lower_than: level]]&lt;/code&gt; in state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#39;s what our function will look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt; @levels %{
    fatal: 0,
    error: 1,
    warn: 2,
    info: 3,
    debug: 4,
    trace: 5
  }

def handle_event(
      {level, _gl, {Logger, message, _timestamp, metadata}},
      options
    ) do
  application = metadata[:application] || :default

  log_event(
    @levels[level],
    @levels[options[:application_config][application][:level_lower_than]],
    message,
    metadata,
    options
  )

  {:ok, options}
end

def log_event(level, level_lower_than, message, metadata, options)
    when level &amp;lt;= level_lower_than do
  Appsignal.Logger.log(
    level,
    to_string(metadata[:group] || options[:group]),
    IO.chardata_to_string(message),
    Enum.into(metadata, %{}),
    options[:format]
  )
end

def log_event(_level, _level_lower_than, _message, _metadata, _options),
  do: :noop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We pull the application config out of state and pass that along with the provided level to the &lt;code&gt;log_event&lt;/code&gt; helper function. That function includes a guard clause that will cause it to no-op if the provided level is &lt;em&gt;higher&lt;/em&gt; than the level configured in &lt;code&gt;runtime.exs&lt;/code&gt; for the given application. If we should in fact log, we do so by calling directly on the &lt;code&gt;AppSignal.Logger.log&lt;/code&gt; function. This allows us to emit logs to AppSignal at a specified level, for a given group, with a message and any metadata.&lt;/p&gt;
&lt;p&gt;With this, we will suppress Phoenix framework logs &lt;em&gt;above&lt;/em&gt; the &lt;code&gt;FATAL&lt;/code&gt; level, but ensure that logs emitted by application code are emitted at &lt;code&gt;INFO&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re hesitant to suppress framework logs in this way, remember that logs are just one piece of the observability puzzle. Rather than recording every instance of a &lt;code&gt;GET /&lt;/code&gt; request, we are more likely to care about trends in serving such requests over time. We want the ability to drill down into the details of &lt;em&gt;some such&lt;/em&gt; requests, especially where they are anomalous (for example, if a request experiences a high degree of latency).&lt;/p&gt;
&lt;p&gt;This is where traces come in, along with other telemetry data, like metrics and exceptions.&lt;/p&gt;
&lt;p&gt;In the next section, we&amp;#39;ll look at how you can use AppSignal to correlate logs with traces and other types of telemetry, giving you a full picture of how your application is performing.&lt;/p&gt;
&lt;h2&gt;Correlating Log Events and Other Telemetry with AppSignal&lt;/h2&gt;
&lt;p&gt;Application logs are just one part of your overall observability posture. They should be used to record specific events of interest in your application&amp;#39;s lifecycle and provide additional details and context in the event of an error or exception.&lt;/p&gt;
&lt;p&gt;You should leverage application logs alongside other telemetry data like metrics, traces, and exception reports to fully observe your application in production.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a very high-level overview of how you can view each type of telemetry data that your application emits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Logs&lt;/strong&gt; record that an event occurred (for example, a failed user log-in attempt).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metrics&lt;/strong&gt; record trends in event occurrences over time. For example, you can record the distribution of request latency to a particular endpoint, or monitor the capacity utilization of your system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traces&lt;/strong&gt; record details of the lifecycle for a particular piece of code flow. For example, drill down into the trace of a specific request to understand possible causes of latency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exception reports&lt;/strong&gt; show when an unexpected or &amp;quot;exceptional&amp;quot; error occurred. If your code encounters an exception, you can see the details of that exception, including the backtrace and full error message.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These telemetry signals become especially powerful when they can be correlated. For example, when viewing a specific exception report, you may want to gain more insight into the performance of your overall system at the time the exception occurred. In this case, the ability to view logs and/or traces from that same timeframe can provide you with the extra information you need to remedy bugs and improve overall application performance.&lt;/p&gt;
&lt;h2&gt;Monitoring Your Logs Using AppSignal&lt;/h2&gt;
&lt;p&gt;Correlating telemetry data can be a particularly hard problem to solve in the observability domain, especially when using different third-party services for things like logging, tracing, and exception reporting. AppSignal provides functionality for managing all of these types of telemetry and empowers you to correlate different types of telemetry data to get the most out of various signals. Let&amp;#39;s take a look at an example now.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll use the &amp;quot;Errors&amp;quot; -&amp;gt; &amp;quot;Issue list&amp;quot; as the entry point for this exercise. I&amp;#39;ve selected an exception report from this list, displayed here:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/exception-report.png&quot; alt=&quot;Exception report&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We can correlate this exception report with some traces emitted by the live view that encountered this error. &lt;em&gt;Note that I&amp;#39;ve configured our application to emit LiveView traces to AppSignal by &lt;a href=&quot;https://docs.appsignal.com/elixir/integrations/phoenix.html&quot;&gt;following the instructions here&lt;/a&gt;.&lt;/em&gt; By clicking on &amp;quot;samples&amp;quot; and selecting an exception sample to examine, we can see the following exception details:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/trace-sample.png&quot; alt=&quot;Trace sample&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now, in addition to the original exception report, we can see other useful information like the event that the live view was trying to handle when the exception occurred and the payload of that event, in addition to the full exception backtrace.&lt;/p&gt;
&lt;p&gt;Finally, we can use the Time Detective feature to explore the full range of telemetry data, including traces, that our application emitted around the time of this exception. If we click on the &amp;quot;Time Detective&amp;quot; action here:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/time-detective-link.png&quot; alt=&quot;Time Detective&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/time-detective-performance.png&quot; alt=&quot;Time Detective Performance&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The &amp;quot;Performance&amp;quot; view brings up some trace samples from the time period that we can drill down into. Here, we can see a list of traces that occurred around the time of the incident, including traces for the various LiveView lifecycle callbacks. From the details in the exception sample, we know this error occurred when an event handler in our live view tried to handle the &lt;code&gt;&amp;quot;update&amp;quot;&lt;/code&gt; message. So, let&amp;#39;s select the &lt;code&gt;handle_event&lt;/code&gt; trace. We&amp;#39;ll see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/handle-event-trace.png&quot; alt=&quot;Event trace&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can also select the &amp;quot;Logs&amp;quot; tab to view logs from this time period.&lt;/p&gt;
&lt;p&gt;The Time Detective tool can be accessed via the logging UI as well. Just expand a given log line and select &amp;quot;Time Detective&amp;quot; from the bottom of the expanded view:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-06/time-detective-from-log-view.png&quot; alt=&quot;Time Detective from Log&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Then you&amp;#39;ll have access to all of the telemetry data that can be correlated to your log statement based on timeframe. This could be especially useful if you see a high volume of a particular request being logged, or note an interesting error log. For any interesting or informative log statements, a deep dive into correlated telemetry data is just a click away.&lt;/p&gt;
&lt;h2&gt;Logging in Phoenix: A Few Final Tips&lt;/h2&gt;
&lt;p&gt;You&amp;#39;re now ready to leverage logging as one part of the overall observability story in your Phoenix application. Just a few guiding rules to keep in mind when you do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prefer structured over unstructured logs so that you can &lt;a href=&quot;https://www.appsignal.com/tour/log-management&quot;&gt;query and analyze your application&amp;#39;s logs with tools like AppSignal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Suppress framework logs to the &lt;code&gt;FATAL&lt;/code&gt; level and emit application logs at &lt;code&gt;INFO&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Treat logs as just one part of your observability posture. Logs are most useful when correlated with other telemetry data, like exceptions and traces.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve covered a lot of ground in this post, so let&amp;#39;s wrap up before you go.&lt;/p&gt;
&lt;p&gt;We discussed the benefit of structured over unstructured logging, and configured our Phoenix application to use logfmt with the console logger backend. We then saw the benefits of structured logging in action in AppSignal.&lt;/p&gt;
&lt;p&gt;Finally, we took our log analysis skills to the next level when we suppressed framework logs and explored how our meaningful application logs correlated with other telemetry data in AppSignal.&lt;/p&gt;
&lt;p&gt;Now take on the world of Phoenix logging. Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Deep Dive into Mutations with Absinthe</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/07/04/a-deep-dive-into-mutations-with-absinthe.html"/>
    <id>https://blog.appsignal.com/2023/07/04/a-deep-dive-into-mutations-with-absinthe.html</id>
    <published>2023-07-04T00:00:00+00:00</published>
    <updated>2023-07-04T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the third part of this series, we&#039;ll create GraphQL mutations with Absinthe.</summary>
    <content type="html">&lt;p&gt;In the last two posts of this series, we saw how easy it is to integrate Absinthe into your app to provide a GraphQL API for querying data. We also shared some useful tips for building and maintaining large schemas and optimizing queries.&lt;/p&gt;
&lt;p&gt;This post will show how we can provide an API to create GraphQL mutations with Absinthe for Elixir.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;A Note on Queries Vs. Mutations in GraphQL&lt;/h2&gt;
&lt;p&gt;GraphQL places a clear distinction between queries and mutations. Technically, we can implement any query to write data to the server. But &lt;a href=&quot;https://graphql.org/learn/queries/#mutations&quot;&gt;GraphQL convention&lt;/a&gt; clearly separates them into different top-level &lt;code&gt;mutation&lt;/code&gt; types.&lt;/p&gt;
&lt;h2&gt;Mutations in GraphQL&lt;/h2&gt;
&lt;p&gt;First, let’s see what a typical mutation looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;mutation CreatePost($post: PostCreateInput!) {
  createPost(post: $post) {
    post {
      id
    }
    errors
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a mutation to create a new post. It accepts a variable named &lt;code&gt;post&lt;/code&gt; of type &lt;code&gt;PostCreateInput&lt;/code&gt; (which is required because &lt;code&gt;!&lt;/code&gt; follows the type name). This variable is passed into the &lt;code&gt;createPost&lt;/code&gt; field inside the top-level &lt;code&gt;mutation&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;The result of that mutation is a &lt;code&gt;post&lt;/code&gt; (which can have further selections) and an &lt;code&gt;errors&lt;/code&gt; array. Note that we have named the mutation &lt;code&gt;CreatePost&lt;/code&gt; but that is just a client-side identifier. Here is what a sample response from this mutation looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;data&amp;quot;: {
    &amp;quot;createPost&amp;quot;: {
      &amp;quot;post&amp;quot;: {
        &amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;
      },
      &amp;quot;errors&amp;quot;: null
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Input Objects with Absinthe for Elixir&lt;/h2&gt;
&lt;p&gt;Let’s see how we can implement this with Absinthe. The first thing we need is an &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Type.InputObject.html&quot;&gt;&lt;code&gt;input_object&lt;/code&gt;&lt;/a&gt; that can be used as a variable for the mutation. Let’s create one now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  enum :post_state_enum do
    value :active
    value :draft
  end

  input_object :post_create_input do
    field :title, non_null(:string)
    field :author_id, non_null(:id)
    field :body, non_null(:string)
    field :state, :post_state_enum, default_value: :draft
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Type.Enum.html&quot;&gt;&lt;code&gt;enum&lt;/code&gt;&lt;/a&gt; macro to create an enum named &lt;code&gt;post_state_enum&lt;/code&gt; with two possible values — &lt;code&gt;draft&lt;/code&gt; and &lt;code&gt;active&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We then use the &lt;code&gt;input_object&lt;/code&gt; macro to define an input object named &lt;code&gt;post_create_input&lt;/code&gt; which has four fields. Note that the definition of fields changes slightly from what we would use in an output type. For example, for fields inside an input object, we can add a &lt;code&gt;default_value&lt;/code&gt; to a non-required field. Absinthe will fill the field in if the user doesn’t provide a value.&lt;/p&gt;
&lt;h2&gt;Defining Mutations in Absinthe&lt;/h2&gt;
&lt;p&gt;Next, let’s define our mutation type in the schema. All individual mutations (like &lt;code&gt;createPost&lt;/code&gt;) will be fields inside this mutation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  mutation do
    field :create_post, non_null(:post_mutation_result) do
      arg :post, non_null(:post_create_input)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use the &lt;code&gt;mutation..do..end&lt;/code&gt; block to define the base mutation type. And inside it, we define a field named &lt;code&gt;create_post&lt;/code&gt;. This takes a single argument named &lt;code&gt;post&lt;/code&gt; of the &lt;code&gt;post_create_input&lt;/code&gt; type defined above. The result of this field is of type &lt;code&gt;post_mutation_result&lt;/code&gt;. We haven’t defined it yet, so let’s do that now.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;object :post_mutation_result do
  field :post, :post
  field :errors, list_of(non_null(:string))
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now on to the interesting part — actually performing the mutation operation. This is similar to what we already did for queries. We will define a resolver to handle it.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;If you remember from &lt;a href=&quot;https://blog.appsignal.com/2023/06/06/absinthe-for-large-elixir-applications.html&quot;&gt;our previous post&lt;/a&gt;, a 3-arity resolver receives the parent object, the attributes, and an &lt;code&gt;Absinthe.Resolution&lt;/code&gt; struct. Let’s define that first to create the post:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Resolvers.PostResolver do
  def create_post(_parent, %{post: attrs}, _resolution) do
    case MyAppWeb.Blog.create_post(attrs) do
      {:ok, post} -&amp;gt;
        {:ok, %{post: post}}
      {:error, changeset} -&amp;gt;
        {:ok, %{errors: translate_changeset_errors(changeset)}}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the resolver, we use the &lt;code&gt;post&lt;/code&gt; attributes to create a post. If that is successful, we respond with the post object (the result map should correspond to the mutation&amp;#39;s result type — &lt;code&gt;post_mutation_result&lt;/code&gt;, in our case). On an error, we respond with the &lt;code&gt;errors&lt;/code&gt;. Note that &lt;a href=&quot;https://gist.github.com/sapandiwakar/fd1642a484826f2e02208d02c014fb55&quot;&gt;&lt;code&gt;translate_changeset_errors&lt;/code&gt;&lt;/a&gt; is a custom helper function that translates &lt;code&gt;Ecto.Changeset&lt;/code&gt; errors into an array of strings.&lt;/p&gt;
&lt;p&gt;With the resolver in place, we can now plug it into our schema to create a post:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  mutation do
    field :create_post, :post_mutation_result do
      arg :post, non_null(:post_create_input)

      resolve &amp;amp;MyAppWeb.Resolvers.PostResolver.create_post/3
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when we execute the above mutation against our schema, Absinthe will call the &lt;code&gt;create_post&lt;/code&gt; function. The return value from the resolver&amp;#39;s &lt;code&gt;{:ok, value}&lt;/code&gt; tuple will then be used as the mutation&amp;#39;s result and returned to the user.&lt;/p&gt;
&lt;h2&gt;Authorization in Your Elixir App with GraphQL and Absinthe&lt;/h2&gt;
&lt;p&gt;Up until now, we have been discussing everything as if we&amp;#39;re using an open public API. But in most apps, this is not how things work. Often, certain APIs are only available to logged-in users, and this is even more important in the case of mutations. Let’s see how we can add authorization to our API.&lt;/p&gt;
&lt;p&gt;First, we will need to identify the users making requests. In the &lt;a href=&quot;https://blog.appsignal.com/2023/05/16/an-introduction-to-absinthe-for-elixir.html#setting-up-your-elixir-app-with-graphql-and-absinthe&quot;&gt;first post of this series&lt;/a&gt;, we used &lt;code&gt;Absinthe.Plug&lt;/code&gt; to handle all the requests coming into the &lt;code&gt;/api&lt;/code&gt; endpoint using the &lt;code&gt;MyAppWeb.Schema&lt;/code&gt; schema. This doesn’t handle any user authorization for us.&lt;/p&gt;
&lt;p&gt;Absinthe provides a &lt;a href=&quot;https://hexdocs.pm/absinthe/context-and-authentication.html&quot;&gt;context&lt;/a&gt; concept containing shared information that might be useful for all queries and mutations. This is passed to all resolver functions that accept an &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Resolution.html&quot;&gt;&lt;code&gt;Absinthe.Resolution&lt;/code&gt;&lt;/a&gt; struct inside the &lt;code&gt;context&lt;/code&gt; field.&lt;/p&gt;
&lt;p&gt;Let’s fix that first to identify users &lt;em&gt;before&lt;/em&gt; a request is forwarded to Absinthe.&lt;/p&gt;
&lt;h2&gt;An Example Using Absinthe Context&lt;/h2&gt;
&lt;p&gt;Update the router in your app to execute an additional plug before forwarding a request:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Router do
  use MyAppWeb, :router

  pipeline :api do
    plug :accepts, [&amp;quot;json&amp;quot;]
  end

  pipeline :graphql do
    plug MyAppWeb.Schema.Context
  end

  scope &amp;quot;/&amp;quot; do
    pipe_through [:api, :graphql]

    forward &amp;quot;/api&amp;quot;, Absinthe.Plug, schema: MyAppWeb.Schema
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ve added a new &lt;code&gt;MyAppWeb.Schema.Context&lt;/code&gt; plug to the requests. Let’s implement it to put a user in the Absinthe context.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema.Context do
  @behaviour Plug

  import Plug.Conn

  #...

  def call(conn, _default) do
    Absinthe.Plug.put_options(conn, context: absinthe_context(conn))
  end

  def absinthe_context(conn) do
    %{conn: fetch_query_params(conn)}
    |&amp;gt; put_user()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; I have intentionally left out some app-specific parts of the plug. Here is the &lt;a href=&quot;https://gist.github.com/sapandiwakar/cd6b988ae8f7d59db579f228fad63210&quot;&gt;full code of that module&lt;/a&gt; if you are interested.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;An interesting part of the code in the above code block is the use of &lt;code&gt;Absinthe.Plug.put_options/2&lt;/code&gt; to set values that &lt;code&gt;Absinthe.Plug&lt;/code&gt; will pass to Absinthe when executing the query/mutation. This is similar to how we use &lt;a href=&quot;https://hexdocs.pm/plug/Plug.Conn.html#assign/3&quot;&gt;&lt;code&gt;Plug.Conn.assign&lt;/code&gt;&lt;/a&gt; to assign something on the conn.&lt;/p&gt;
&lt;p&gt;Internally, &lt;code&gt;Absinthe.Plug&lt;/code&gt; puts a private assign inside the &lt;code&gt;conn&lt;/code&gt; and passes it as the third parameter to &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.html#run/3&quot;&gt;&lt;code&gt;Absinthe.run/3&lt;/code&gt;&lt;/a&gt; when executing the document. The &lt;code&gt;context&lt;/code&gt; option we use above is a special value that Absinthe will then pass to all resolvers inside the &lt;code&gt;Absinthe.Resolution&lt;/code&gt; struct.&lt;/p&gt;
&lt;p&gt;Now let’s update our &lt;code&gt;create_post/3&lt;/code&gt; resolver function to use this context and deny the request if the user isn’t present.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Resolvers.PostResolver do
  def create_post(
    _parent,
    %{post: attrs},
    %Absinthe.Resolution{context: %{user: nil}}
  ) do
    {:error, &amp;quot;unauthorized&amp;quot;}
  end

  def create_post(_parent, %{post: attrs}, %Absinthe.Resolution{}) do
    case MyAppWeb.Blog.create_post(attrs) do
      {:ok, post} -&amp;gt;
        {:ok, %{post: post}}
      {:error, changeset} -&amp;gt;
        {:ok, %{errors: translate_changeset_errors(changeset)}}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If a resolver function returns an error tuple, Absinthe will not resolve that field and adds an error to the response.&lt;/p&gt;
&lt;p&gt;This is just one example of how to use Absinthe context. There are many more advanced potential use cases. For example, you might want to automatically set a user’s id as the post author, instead of accepting an &lt;code&gt;author_id&lt;/code&gt; in the &lt;code&gt;post_create_input&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Middleware in Absinthe for Elixir&lt;/h2&gt;
&lt;p&gt;We have used context to authorize a user during resolution. But if we have many fields to handle, this soon becomes too cumbersome. Absinthe provides middleware to handle such cases.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s assume that several fields require a user to be present when performing an operation. Instead of updating the resolver function for all those fields, wouldn’t it be better if we could just write &lt;code&gt;middleware MyAppWeb.Schema.RequireUser&lt;/code&gt; in the field definition?&lt;/p&gt;
&lt;p&gt;We can do that using the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Middleware.html#module-the-middleware-2-macro&quot;&gt;&lt;code&gt;middleware/2&lt;/code&gt; macro&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  mutation do
    field :create_post, :post_mutation_result do
      arg :post, non_null(:post_create_input)

      middleware MyAppWeb.Schema.RequireUser

      resolve &amp;amp;MyAppWeb.Resolvers.PostResolver.create_post/3
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The argument to &lt;code&gt;middleware&lt;/code&gt; is a module that implements the &lt;code&gt;Absinthe.Middleware&lt;/code&gt; behaviour. The module should start a &lt;code&gt;call/2&lt;/code&gt; function that receives an &lt;code&gt;Absinthe.Resolution&lt;/code&gt; struct as the first argument.&lt;/p&gt;
&lt;p&gt;The second argument is whatever is passed to the &lt;code&gt;middleware/2&lt;/code&gt; macro. We don’t pass anything above, so it&amp;#39;s nil by default. The &lt;code&gt;call/2&lt;/code&gt; function should return an updated &lt;code&gt;Absinthe.Resolution&lt;/code&gt; struct.&lt;/p&gt;
&lt;h3&gt;Implement &lt;code&gt;RequireUser&lt;/code&gt; Middleware&lt;/h3&gt;
&lt;p&gt;Let’s implement the &lt;code&gt;RequireUser&lt;/code&gt; middleware now to stop requests if a user is not present:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SpendraWeb.Schema.RequireUser do
  @behaviour Absinthe.Middleware

  def call(%Absinthe.Resolution{state: :resolved} = resolution, _config), do: resolution

  def call(%Absinthe.Resolution{context: {user: nil}} = resolution, _config) do
    Absinthe.Resolution.put_result(
      resolution,
      {:error, &amp;quot;You must be logged in to access this API&amp;quot;}
    )
  end

  def call(%Absinthe.Resolution{} = resolution, _config), do: resolution
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The middle clause is the most important. Here, we receive a context with a &lt;code&gt;nil&lt;/code&gt; value for the user. We use &lt;code&gt;Absinthe.Resolution.put_result&lt;/code&gt; to mark that the resolution is now complete. It does two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Marks the &lt;code&gt;state&lt;/code&gt; of the resolution as &lt;code&gt;resolved&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Puts the specified value as the resolution result. Here we use an error tuple to signal that this is an erroneous response.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We also have a special clause at the beginning that checks for the resolution&amp;#39;s existing state. If you are using multiple middlewares in your app, this is important. It avoids a middleware running on a resolution that has already been resolved.&lt;/p&gt;
&lt;p&gt;Finally, if a resolution&amp;#39;s state is not already &lt;code&gt;resolved&lt;/code&gt; and we have a user in the context, we just return the original resolution struct without any modifications. This allows execution to proceed.&lt;/p&gt;
&lt;h3&gt;Chaining Middleware&lt;/h3&gt;
&lt;p&gt;The great thing about middleware is that it can be chained. For example, we might have several user roles and only want authors to be able to create posts. We can use multiple middleware clauses that each perform a single task before the final resolution.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;field :create_post, :post_mutation_result do
  middleware MyAppWeb.Schema.RequireUser

  middleware MyAppWeb.Schema.RequireAuthor

  resolve &amp;amp;MyAppWeb.Resolvers.PostResolver.create_post/3
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In fact, &lt;code&gt;resolve&lt;/code&gt; itself is just a middleware which roughly translates to &lt;code&gt;middleware Absinthe.Resolution, unquote(function_ast)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another important point about middlewares is that they are executed in the order they are defined in a field. So in the above example, first &lt;code&gt;RequireUser&lt;/code&gt; will be executed, followed by &lt;code&gt;RequireAuthor&lt;/code&gt; and, finally, the resolver.&lt;/p&gt;
&lt;p&gt;It is also possible to use middleware after a resolve call — for example, to handle resolution errors.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this post, we created GraphQL mutations with Absinthe. We also added a custom plug to put shared information in an Absinthe context and defined middleware to handle common tasks like authorization.&lt;/p&gt;
&lt;p&gt;In the next and final part of this series, we will discuss advanced GraphQL use cases like subscriptions (including how to implement and deliver subscriptions over a WebSocket connection).&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Create and Open a Modal in Phoenix 1.7</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/06/20/create-and-open-a-modal-in-phoenix-1-7.html"/>
    <id>https://blog.appsignal.com/2023/06/20/create-and-open-a-modal-in-phoenix-1-7.html</id>
    <published>2023-06-20T00:00:00+00:00</published>
    <updated>2023-06-20T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In part one of this series, we&#039;ll add a modal to an example Phoenix application.</summary>
    <content type="html">&lt;p&gt;Phoenix 1.7 came out this year with a whole host of exciting features, including
&lt;a href=&quot;https://hexdocs.pm/phoenix/Phoenix.VerifiedRoutes.html&quot;&gt;verified routes&lt;/a&gt; and some great built-in &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind&lt;/a&gt; components. These components are a fantastic start, but they are
not made to be a fully general design system. We should expect to modify components to fit our
specific needs. However, knowing where to start can be difficult.&lt;/p&gt;
&lt;p&gt;In this three-part series,
we&amp;#39;ll take a fresh Phoenix app and create a working UI using generated components.&lt;/p&gt;
&lt;p&gt;In this part, we
will add a modal to a page and open it on demand.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;The UI of Our Phoenix App — Setup&lt;/h2&gt;
&lt;p&gt;The UI we will implement is a list of data and two modals for that data: a create modal
and an edit modal. Our example will be a spectacular pet shop called Petacular.&lt;/p&gt;
&lt;p&gt;To begin, let&amp;#39;s bootstrap the app. If you wish to write the command yourself, first ensure
you have the latest Phoenix installer with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mix archive.install hex phx_new
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mix phx.new petacular
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will bootstrap the project and generate the core components we&amp;#39;ll use in our examples.
To illustrate the various steps in this article, I have included a &lt;a href=&quot;https://github.com/Adzz/petacular&quot;&gt;companion repo&lt;/a&gt; with commits for each step. &lt;a href=&quot;https://github.com/Adzz/petacular/commit/9f4233394a23423c5a5b71e851c173d2debb0556&quot;&gt;This commit&lt;/a&gt; shows us everything that gets generated in the
above command. Of particular interest is &lt;a href=&quot;https://github.com/Adzz/petacular/blob/9f4233394a23423c5a5b71e851c173d2debb0556/lib/petacular_web/components/core_components.ex&quot;&gt;this module&lt;/a&gt;
which contains all of the generated components we will be exploring.&lt;/p&gt;
&lt;p&gt;The components use Tailwind CSS for styling and are passed attributes and/or
slots, as appropriate. We will leverage a few below, but first, we will need a database.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Adzz/petacular/commit/df785b8cd2a470e6d2a52950c39c521f5e5368ee&quot;&gt;Check out this commit&lt;/a&gt; for everything we need to get a db working with docker. &lt;a href=&quot;https://github.com/Adzz/petacular/commit/abbdb457a780125cf66f041ff3eb5f3952be6866&quot;&gt;This commit&lt;/a&gt;
adds a migration and creates a few schemas we will use for our example: a list of pets
and their preferences. Finally, you can see how &lt;a href=&quot;https://github.com/Adzz/petacular/commit/8a1b3f4bfa96d41afd674ac0ce102f9c33bcb62b&quot;&gt;this commit&lt;/a&gt; makes the home page a LiveView page and
introduces some very basic styling.&lt;/p&gt;
&lt;h2&gt;What Is a Modal in Phoenix?&lt;/h2&gt;
&lt;p&gt;The initial homepage looks like this (found in &lt;code&gt;lib/petacular_web/pages/home_live.ex&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@impl true
def render(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;h1 class=&amp;quot;font-semibold text-3xl mb-4&amp;quot;&amp;gt;Pets&amp;lt;/h1&amp;gt;
  &amp;lt;PetacularWeb.CoreComponents.button&amp;gt;
    Add New Pet +
  &amp;lt;/PetacularWeb.CoreComponents.button&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I have included a built-in component from the generated &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex&quot;&gt;&lt;code&gt;PetacularWeb.CoreComponents&lt;/code&gt;&lt;/a&gt;
module (found in &lt;code&gt;lib/petacular_web/components/core_components.ex&lt;/code&gt;) — a button. The &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L213&quot;&gt;button is defined here&lt;/a&gt; and it is simple to use:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in /lib/petacular_web/pages/home_live.ex
...
~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;PetacularWeb.CoreComponents.button&amp;gt;
      Add New Pet +
    &amp;lt;/PetacularWeb.CoreComponents.button&amp;gt;
&amp;quot;&amp;quot;&amp;quot;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We would love for this to open a modal that contains a form for adding a pet. To do
that, let&amp;#39;s look at &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L44&quot;&gt;the modal&lt;/a&gt; in the &lt;code&gt;PetacularWeb.CoreComponents&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;This is a &lt;em&gt;function&lt;/em&gt; component, meaning it does not have a state. It&amp;#39;s just a bundle of
markup and styling. It has some &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#module-attributes&quot;&gt;&lt;code&gt;attrs&lt;/code&gt;&lt;/a&gt; — for example, &lt;code&gt;attr :show, :boolean, default: false&lt;/code&gt;, and one &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#module-slots&quot;&gt;slot&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;What Are &lt;code&gt;attr&lt;/code&gt;s and Slots?&lt;/h3&gt;
&lt;p&gt;An &lt;code&gt;attr&lt;/code&gt; defines data that&amp;#39;s expected to pass. Some &lt;code&gt;attr&lt;/code&gt;s are required, and some have a default
value instead. A slot is space for nested HTML and can be named or not. In essence,
slots let you provide your own markup and appear as children of a function component&amp;#39;s element.&lt;/p&gt;
&lt;p&gt;We can see the slot is called &lt;code&gt;:inner_block&lt;/code&gt;, a special name for the modal. Everything
inside of the &lt;code&gt;&amp;lt;.modal&amp;gt;&lt;/code&gt; tags will be treated as the &lt;code&gt;:inner_block&lt;/code&gt; slot. So, &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L27&quot;&gt;in the function docs&lt;/a&gt;, the modal component looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;.modal id=&amp;quot;confirm-modal&amp;quot;&amp;gt;
  This is a modal.
&amp;lt;/.modal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The text &lt;code&gt;This is a modal.&lt;/code&gt; is treated as the &lt;code&gt;:inner_block&lt;/code&gt;. In contrast, we can name a
slot. Then we designate the contents of that slot by putting content in between two
tags that use the slot&amp;#39;s name. For example, &lt;code&gt;CoreComponents&lt;/code&gt; has a &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L398&quot;&gt;&lt;code&gt;&amp;lt;.header&amp;gt;&lt;/code&gt;&lt;/a&gt; component with an optional &lt;code&gt;:subtitle&lt;/code&gt; slot. To provide a subtitle,
we do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;CoreComponents.header&amp;gt;
  This is my title.
  &amp;lt;:subtitle&amp;gt;
    This is my subtitle. There are many like it but this one is mine.
  &amp;lt;/:subtitle&amp;gt;
&amp;lt;/CoreComponents.header&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Making the Modal Appear in Phoenix&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L27&quot;&gt;docs for the modal&lt;/a&gt;
give us an indication of what the modal needs to look for. We need
to provide an ID that is targeted by the &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L603&quot;&gt;&lt;code&gt;hide_modal&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L591&quot;&gt;&lt;code&gt;show_modal&lt;/code&gt;&lt;/a&gt; functions. Let&amp;#39;s look at how they work first. The show modal is defined like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/components/core_components.ex

def show_modal(js \\ %JS{}, id) when is_binary(id) do
  js
  |&amp;gt; JS.show(to: &amp;quot;##{id}&amp;quot;)
  |&amp;gt; JS.show(
    to: &amp;quot;##{id}-bg&amp;quot;,
    transition: {&amp;quot;transition-all transform ease-out duration-300&amp;quot;, &amp;quot;opacity-0&amp;quot;, &amp;quot;opacity-100&amp;quot;}
  )
  |&amp;gt; show(&amp;quot;##{id}-container&amp;quot;)
  |&amp;gt; JS.add_class(&amp;quot;overflow-hidden&amp;quot;, to: &amp;quot;body&amp;quot;)
  |&amp;gt; JS.focus_first(to: &amp;quot;##{id}-content&amp;quot;)
end

def show(js \\ %JS{}, selector) do
  JS.show(js,
    to: selector,
    transition:
      {&amp;quot;transition-all transform ease-out duration-300&amp;quot;,
       &amp;quot;opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95&amp;quot;,
       &amp;quot;opacity-100 translate-y-0 sm:scale-100&amp;quot;}
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses the new(ish) &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.JS.html&quot;&gt;&lt;code&gt;JS&lt;/code&gt; module&lt;/a&gt; to execute simple JavaScript functions. It accepts and uses an ID to identify
the element we want to show. Upon appearing, the show modal does some simple animations to ease it
into view and focuses the page onto the first focus-able element, if there is one.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;&lt;code&gt;hide_modal&lt;/code&gt;
does the same, but in reverse:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in lib/petacular_web/components/core_components.ex

def hide_modal(js \\ %JS{}, id) do
  js
  |&amp;gt; JS.hide(
    to: &amp;quot;##{id}-bg&amp;quot;,
    transition: {&amp;quot;transition-all transform ease-in duration-200&amp;quot;, &amp;quot;opacity-100&amp;quot;, &amp;quot;opacity-0&amp;quot;}
  )
  |&amp;gt; hide(&amp;quot;##{id}-container&amp;quot;)
  |&amp;gt; JS.hide(to: &amp;quot;##{id}&amp;quot;, transition: {&amp;quot;block&amp;quot;, &amp;quot;block&amp;quot;, &amp;quot;hidden&amp;quot;})
  |&amp;gt; JS.remove_class(&amp;quot;overflow-hidden&amp;quot;, to: &amp;quot;body&amp;quot;)
  |&amp;gt; JS.pop_focus()
end

def hide(js \\ %JS{}, selector) do
  JS.hide(js,
    to: selector,
    time: 200,
    transition:
      {&amp;quot;transition-all transform ease-in duration-200&amp;quot;,
       &amp;quot;opacity-100 translate-y-0 sm:scale-100&amp;quot;,
       &amp;quot;opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95&amp;quot;}
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Calling the &lt;code&gt;show_modal&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;With a button click, we call the &lt;code&gt;show_modal&lt;/code&gt;
function to make the modal appear. To close the modal, we need a button on the modal itself
that calls &lt;code&gt;hide_modal&lt;/code&gt;. Luckily, this is &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L72&quot;&gt;implemented for us&lt;/a&gt;, so we don&amp;#39;t need to worry about it.&lt;/p&gt;
&lt;p&gt;From &lt;a href=&quot;https://github.com/Adzz/petacular/blob/main/lib/petacular_web/components/core_components.ex#L34&quot;&gt;our function docs&lt;/a&gt;, we see that we need some content inside the modal. Like the button
we used earlier, the modal uses an &lt;code&gt;:inner_block&lt;/code&gt; slot. That means anything inside the
modal tags will appear on the page as the &lt;code&gt;:inner_block&lt;/code&gt;. We can keep this very
simple. Something like the following will work for now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in /lib/petacular_web/pages/home_live.ex

&amp;lt;PetacularWeb.CoreComponents.modal id=&amp;quot;create_modal&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Add a pet.&amp;lt;/h2&amp;gt;
&amp;lt;/PetacularWeb.CoreComponents.modal&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can put this inside our homepage and have a click trigger the &lt;code&gt;show_modal&lt;/code&gt; function by
adding &lt;code&gt;phx-click&lt;/code&gt; onto the button we used earlier. Usually, we set &lt;code&gt;phx-click&lt;/code&gt; to a string,
and clicking it sends an event to the backend using that string as the event name. But we
may also provide a &lt;code&gt;JS&lt;/code&gt; function or a chain of them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in /lib/petacular_web/pages/home_live.ex

&amp;lt;PetacularWeb.CoreComponents.button phx-click={
  PetacularWeb.CoreComponents.show_modal(&amp;quot;create_modal&amp;quot;)
}&amp;gt;
  Add New Pet +
&amp;lt;/PetacularWeb.CoreComponents.button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting it all together, we end up with something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in /lib/petacular_web/pages/home_live.ex

~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;h1 class=&amp;quot;font-semibold text-3xl mb-4&amp;quot;&amp;gt;Pets&amp;lt;/h1&amp;gt;

  &amp;lt;PetacularWeb.CoreComponents.modal id=&amp;quot;create_modal&amp;quot;&amp;gt;
    &amp;lt;h2&amp;gt;Add a pet.&amp;lt;/h2&amp;gt;
  &amp;lt;/PetacularWeb.CoreComponents.modal&amp;gt;

  &amp;lt;PetacularWeb.CoreComponents.button phx-click={
    PetacularWeb.CoreComponents.show_modal(&amp;quot;create_modal&amp;quot;)
  }&amp;gt;
    Add New Pet +
  &amp;lt;/PetacularWeb.CoreComponents.button&amp;gt;
&amp;quot;&amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when you click the button, the modal will open! 🎉&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Adzz/petacular/commit/dde845c66ed42d7d90290ff19d4a1d5052f556ed&quot;&gt;See the full diff of changes&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we used Phoenix 1.7&amp;#39;s generated core components to create a modal and open it.&lt;/p&gt;
&lt;p&gt;In part two, we&amp;#39;ll add the edit form.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Absinthe for Large Elixir Applications</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/06/06/absinthe-for-large-elixir-applications.html"/>
    <id>https://blog.appsignal.com/2023/06/06/absinthe-for-large-elixir-applications.html</id>
    <published>2023-06-06T00:00:00+00:00</published>
    <updated>2023-06-06T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how you can best use Absinthe for data-heavy Elixir applications.</summary>
    <content type="html">&lt;p&gt;In our introduction to Absinthe, we covered the basics of Absinthe and GraphQL for an Elixir application.&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;ll dig deeper and see how we can customize Absinthe for larger-scale Elixir applications.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Defining Resolvers for a Large Elixir App&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve seen that creating a query and returning a result in Absinthe is really easy.
But if you have big resolution logic, the schema can soon get very heavy.
It&amp;#39;s common practice to define resolver functions in a separate module for large apps using Absinthe.&lt;/p&gt;
&lt;p&gt;First, create a module that defines functions acting as field resolvers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app_web/schema/resolvers/blog.ex
defmodule MyAppWeb.Schema.Resolvers.Blog do
  def post(%{id: post_id}, _resolution) do
    # complex resolution logic here
    # post = ...
    {:ok, post}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, update your schema to use this resolver:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  query do
    field :post, :post do
      arg :id, non_null(:id)
      resolve &amp;amp;MyAppWeb.Schema.Resolvers.Blog.post/2
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also allows you to unit-test that resolution logic separately from your GraphQL integration tests. We will discuss more about testing schemas later on in this series.&lt;/p&gt;
&lt;p&gt;The resolvers additionally help you to reduce code duplication at several places in your schema.
For example, let&amp;#39;s say you need to expose a field under a different name from what is defined on the struct.
We can build the object like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;object :post do
  # ...
  field :published_at, :datetime do
    resolve fn %Post{} = post, _args, _resolution -&amp;gt;
      {:ok, post.inserted_at}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you find yourself doing that at several places in the schema, it might be better to create a resolver:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema.Resolvers.Base do
  @doc &amp;quot;&amp;quot;&amp;quot;
  Returns a resolver function that returns the value at `field` from `parent`
  &amp;quot;&amp;quot;&amp;quot;
  def alias(field) do
    fn parent, _args, _resolution -&amp;gt; {:ok, Map.get(parent, field)} end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then use it in your object like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;object :post do
  # ...
  field :published_at, :datetime, resolve: Resolvers.Base.alias(:inserted_at)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Avoiding N+1 Queries in Elixir&lt;/h2&gt;
&lt;p&gt;Let’s get back to our schema, but with a query that returns a list of posts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  object :post do
    # ...
    field :author, non_null(:author),
      resolve: &amp;amp;Resolvers.Blog.post_author/3
  end

  query do
    field :posts, non_null(list_of(:post)),
      resolve: &amp;amp;Resolvers.Blog.list_posts/2
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is the full &lt;a href=&quot;https://gist.github.com/sapandiwakar/2585851aa844b9cbf4f7fb812f049ca5#file-blog-ex&quot;&gt;&lt;code&gt;Resolvers.Blog&lt;/code&gt;&lt;/a&gt; if you are interested.&lt;/p&gt;
&lt;p&gt;Now, perform a query that includes the author of each post:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;query {
  posts {
    id
    author {
      id
      firstName
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When this query is executed, we first fetch all posts from the database. Then we fetch the author by their id for each post — that&amp;#39;s not very efficient.&lt;/p&gt;
&lt;p&gt;But that’s an easy problem to solve. We can just preload the authors in &lt;code&gt;Resolvers.Blog.list_posts/2&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;However, what if someone makes a query that doesn’t need an author?
We will still be unnecessarily fetching all authors, defeating the whole purpose of having a composable query like this.&lt;/p&gt;
&lt;p&gt;One possible solution is to be smart when resolving the initial list of posts and load authors only when the user has selected the &lt;code&gt;author&lt;/code&gt; field in the query.
If you remember, we get an &lt;code&gt;Absinthe.Resolution&lt;/code&gt; struct as the last argument to the resolver function.
&lt;code&gt;resolution.definition.selections&lt;/code&gt; contains all the selected fields (&lt;code&gt;Absinthe.Blueprint.Document.Field&lt;/code&gt; structs).&lt;/p&gt;
&lt;p&gt;We can check if the &lt;code&gt;author&lt;/code&gt; was selected here, and preload it right there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Resolvers.Blog do
  def list_posts(%{}, %Absinthe.Resolution{} = res) do
    posts = Blog.list_posts()

    res.definition.selections
    |&amp;gt; Enum.any?(&amp;amp;(&amp;amp;1.name == &amp;quot;author&amp;quot;))
    |&amp;gt; if do
      {:ok, Repo.preload(posts, :author)}
    else
      {:ok, posts}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That works, but if you have many fields (or several nested levels), it can soon become too cumbersome.
This is where &lt;a href=&quot;https://hexdocs.pm/absinthe/dataloader.html&quot;&gt;&lt;code&gt;dataloader&lt;/code&gt;&lt;/a&gt; can help.&lt;/p&gt;
&lt;h2&gt;Dataloader to the Rescue!&lt;/h2&gt;
&lt;p&gt;Dataloader provides an efficient way to load linked data by batching queries.
It does this by first performing a full pass through the query resolution phase, collecting all the ids of objects to be loaded. Dataloader then loads them all in one go instead of making a request to the database for each of them separately.&lt;/p&gt;
&lt;p&gt;It’s a separate dependency, so first add it to your &lt;code&gt;mix.exs&lt;/code&gt; inside &lt;code&gt;deps&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You then need a one-time setup in your schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  # ... schema definition here ...

  # Add dataloader to the context
  def context(ctx) do
    loader =
      Dataloader.new
      |&amp;gt; Dataloader.add_source(Blog, Blog.data())
      # ... add other sources here ...

    Map.put(ctx, :loader, loader)
  end

  # Add dataloader to the plugins
  def plugins do
    [Absinthe.Middleware.Dataloader] ++ Absinthe.Plugin.defaults()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can add custom fields to the context through the &lt;code&gt;context&lt;/code&gt; method in the schema.
The context&amp;#39;s value is available to all steps in the GraphQL request cycle (e.g., inside resolvers or middleware) inside the &lt;code&gt;%Absinthe.Resolution{}&lt;/code&gt; struct.
Context is also where we usually store user details if we authenticate users.
Check out the &lt;a href=&quot;https://hexdocs.pm/absinthe/context-and-authentication.html&quot;&gt;Absinthe Context and Authentication&lt;/a&gt; guide to explore this further.&lt;/p&gt;
&lt;p&gt;In addition, we add &lt;code&gt;dataloader&lt;/code&gt; to &lt;code&gt;plugins&lt;/code&gt; using the &lt;code&gt;plugins/0&lt;/code&gt; callback on the schema.
This allows &lt;code&gt;dataloader&lt;/code&gt; to hook into the resolution pipeline.
If you want to learn more about plugins, read the &lt;a href=&quot;https://hexdocs.pm/absinthe/middleware-and-plugins.html&quot;&gt;Writing Middleware and Plugins guide for Absinthe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DataLoader.add_source/3&lt;/code&gt; expects the name of the data source as its second argument and a module implementing the &lt;code&gt;Dataloader.Source&lt;/code&gt; protocol. Dataloader supports an &lt;a href=&quot;https://hexdocs.pm/dataloader/Dataloader.Ecto.html&quot;&gt;Ecto-based data source&lt;/a&gt; out of the box, which is what we will need for our example.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s update our Phoenix context (&lt;code&gt;Blog&lt;/code&gt; in our example) to return the Ecto data source from &lt;code&gt;data/0&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/blog.ex
defmodule MyApp.Blog do
  def data(), do: Dataloader.Ecto.new(MyApp.Repo, query: &amp;amp;query/2)

  def query(queryable, _params), do: queryable
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It isn&amp;#39;t really documented very well, but if you are feeling adventurous, most of the data-loading magic lies inside the &lt;a href=&quot;https://github.com/absinthe-graphql/dataloader/blob/master/lib/dataloader/ecto.ex&quot;&gt;Ecto data source&lt;/a&gt;.
It uses the &lt;code&gt;query/2&lt;/code&gt; function we passed to generate a base query when it needs to load some data.&lt;/p&gt;
&lt;p&gt;For example, if we try to load &lt;code&gt;Author&lt;/code&gt; with ids 1 through 5, it will make a single query like &lt;code&gt;from a in Author, where a.id in [1, 2, 3, 4, 5]&lt;/code&gt;, instead of making 5 different queries.&lt;/p&gt;
&lt;p&gt;This function is our opportunity to filter results and return a query that will finally be used to fetch the items.
For now, we just return the queryable as it is, which means that we don’t need any special filtering.&lt;/p&gt;
&lt;h2&gt;Use Dataloader Inside the Absinthe Schema&lt;/h2&gt;
&lt;p&gt;To use Dataloader inside our schema, we must now modify our object &lt;code&gt;post&lt;/code&gt; to use the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Resolution.Helpers.html#dataloader/3&quot;&gt;&lt;code&gt;dataloader&lt;/code&gt; helper&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Absinthe.Resolution.Helpers, only: [dataloader: 2]

object :post do
  # ... other fields
  field :author, non_null(:author),
    resolve: dataloader(MyApp.Blog, :author)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The first argument to &lt;code&gt;dataloader/2&lt;/code&gt; is the source name (as registered in the schema).&lt;/li&gt;
&lt;li&gt;The next argument is the name of the field in the parent object (&lt;code&gt;author&lt;/code&gt; field in parent object &lt;code&gt;post&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that the data source should be the one that will resolve the field. So if the post belongs to an author with type &lt;code&gt;MyApp.Accounts.User&lt;/code&gt;, you must use &lt;code&gt;dataloader(MyApp.Accounts, :author)&lt;/code&gt; as the resolver and support &lt;code&gt;data/0&lt;/code&gt; and &lt;code&gt;query/2&lt;/code&gt; inside the &lt;code&gt;Accounts&lt;/code&gt; context.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/sapandiwakar/067b283d14905f0c9dcafb378c783cd7&quot;&gt;Here is the full code&lt;/a&gt; if you are interested. I know it&amp;#39;s a lot to take in, so let&amp;#39;s go through the execution of the query above.&lt;/p&gt;
&lt;p&gt;Absinthe first invokes our posts resolver (&lt;code&gt;Resolvers.Blog.list_posts/2&lt;/code&gt;), and returns the list of posts.
Absinthe then checks for the fields it needs inside &lt;code&gt;post&lt;/code&gt; and encounters a selection for &lt;code&gt;author&lt;/code&gt;.
This is where dataloader takes over:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It collects the &lt;code&gt;author_id&lt;/code&gt; for all posts that will be returned in our result. Let&amp;#39;s say we need to load authors &lt;code&gt;[1, 2, 3, 4, 5]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It then calls &lt;code&gt;MyApp.Blog.query(Author, %{})&lt;/code&gt; to get the initial query. In our example, we are simply returning &lt;code&gt;Author&lt;/code&gt; (but in a real application, this could be filtered by business case — for example, if we need only authors that have an active account, we could return &lt;code&gt;where(queryable, [a], a.active)&lt;/code&gt;, instead of just returning &lt;code&gt;queryable&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Finally, it loads the required ids from the above query — &lt;code&gt;from a in Author, where a.id in [1, 2, 3, 4, 5]&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see, we only performed a single query instead of 5 different ones.&lt;/p&gt;
&lt;p&gt;Nesting also works out of the box, so if each author has an &lt;code&gt;organization&lt;/code&gt; field and we select that in the query, Dataloader will load all organizations in one batch.&lt;/p&gt;
&lt;h2&gt;Organizing Your Absinthe Schema with Imports&lt;/h2&gt;
&lt;p&gt;As your schema starts growing, you will soon notice that putting all type definitions and query fields in the same file is not sensible.
This is where &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#import_types/2&quot;&gt;&lt;code&gt;import_types&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#import_fields/2&quot;&gt;&lt;code&gt;import_fields&lt;/code&gt;&lt;/a&gt; come into play.&lt;/p&gt;
&lt;p&gt;The level to split at depends on the size of your API and your application, but it is a common practice to split by business context (the same as your Phoenix contexts).&lt;/p&gt;
&lt;p&gt;Here is a structure that works well.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a module that contains queries (and another for mutations) related to each model:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app_web/schema/types/blog/post/queries.ex
defmodule MyAppWeb.Schema.Types.Blog.Post.Queries do
  use Absinthe.Schema.Notation

  object :post_queries do
    field :posts, list_of(:post), resolve: Resolvers.Blog.posts/2
    # ... all queries related to post here
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a module for types related to each model. Also import the query and mutation types here.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app_web/schema/types/blog/post.ex
defmodule MyAppWeb.Schema.Types.Blog.Post do
  use Absinthe.Schema.Notation

  import_types(MyAppWeb.Schema.Types.Blog.Post.Queries)
  import_types(MyAppWeb.Schema.Types.Blog.Post.Mutations)

  object :post do
    field :title, not_null(:string)
    # ...
  end

  # all types related to blog here
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a module for types related to each context. This should only import the types from model-specific modules.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app_web/schema/types/blog.ex
defmodule MyAppWeb.Schema.Types.Blog do
  use Absinthe.Schema.Notation

  alias MyAppWeb.Schema.Types

  import_types(Types.Blog.Post)
  # ... import all types related to blog here

  object :blog_queries do
    import_fields(:post_queries)
    # ... import all queries related to blog here
  end

  object :blog_mutations do
    import_fields(:post_mutations)
    # ... import all queries related to blog here
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, import the context-specific types to your schema.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app_web/schema.ex
defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  import_types(MyAppWeb.Schema.Types.Blog)

  query do
    import_fields :blog_queries
  end

  mutation do
    import_fields :blog_mutations
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This way, your schema remains very clear, declaring only what it imports. All specific queries are further down the pipeline.&lt;/p&gt;
&lt;p&gt;This may seem like overkill for our small API example.
But we have been using it in production for a large app with several contexts, and it’s been a boon to keep our schema manageable.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this post, the second part of our series on Absinthe, we customized Absinthe for an Elixir application pushing a lot of data. We started by defining resolvers for a big Elixir application and covered how to avoid N+1 queries.&lt;/p&gt;
&lt;p&gt;Finally, we dived into Dataloader (which helps to load linked data) in some detail and explored how to organize our Absinthe schema.&lt;/p&gt;
&lt;p&gt;Next up, we&amp;#39;ll look at creating mutations and subscriptions with Absinthe.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Tackling Performance Issues in Ecto Applications</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/05/23/tackling-performance-issues-in-ecto-applications.html"/>
    <id>https://blog.appsignal.com/2023/05/23/tackling-performance-issues-in-ecto-applications.html</id>
    <published>2023-05-23T00:00:00+00:00</published>
    <updated>2023-05-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s dive into three common performance issues in Ecto applications and see how to fix them.</summary>
    <content type="html">&lt;p&gt;Ecto can be considered &lt;em&gt;the&lt;/em&gt; standard database wrapper and query generator for
Elixir, enabling developers to interact with databases efficiently.&lt;/p&gt;
&lt;p&gt;However, inefficient queries or misconfigurations still can (and will) happen.
Addressing these issues is crucial for a smooth user experience.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll explore three common performance issues in Ecto
applications:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;N+1 query problem:&lt;/strong&gt; You get excessive redundant queries from retrieving related data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inefficient query execution:&lt;/strong&gt; Poorly designed queries will strain a database.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Connection pooling and concurrency issues:&lt;/strong&gt; Bottlenecks and slow response times are caused by configuration or concurrency problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;#39;ll discuss how to detect each issue, as well as their common causes and solutions, so you can optimize your Elixir applications for peak performance.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start!&lt;/p&gt;
&lt;h2&gt;The N+1 Query Problem&lt;/h2&gt;
&lt;p&gt;The N+1 query problem occurs when an application loads a parent record and its
associated child records in separate queries.&lt;/p&gt;
&lt;p&gt;This leads to one query for the parent record (1) and one query for each
child record (N), resulting in N+1 queries in total. This issue can cause a
significant performance hit due to an excessive number of redundant queries.&lt;/p&gt;
&lt;h3&gt;Detecting the Problem in Elixir&lt;/h3&gt;
&lt;p&gt;Suppose we have a &lt;code&gt;User&lt;/code&gt; schema on a many-to-many relationship with a &lt;code&gt;Role&lt;/code&gt;
schema. We&amp;#39;ll call the schema that associates the two &lt;code&gt;RoleAssignment&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/my_app/user.ex
defmodule MyApp.User do
  use Ecto.Schema

  schema &amp;quot;users&amp;quot; do
    field :name, :string

    has_many :role_assignments, MyApp.RoleAssignment, foreign_key: :user_id

    timestamps()
  end
end

# my_app/lib/my_app/role.ex
defmodule MyApp.Role do
  use Ecto.Schema
  import Ecto.Changeset

  schema &amp;quot;roles&amp;quot; do
    field :name, :string

    has_many :role_assignments, MyApp.RoleAssignment, foreign_key: :role_id

    timestamps()
  end
end

# my_app/lib/my_app/role_assignment.ex
defmodule MyApp.RoleAssignment do
  use Ecto.Schema

  schema &amp;quot;role_assignments&amp;quot; do
    belongs_to :role, MyApp.Role, foreign_key: :role_id
    belongs_to :user, MyApp.User, foreign_key: :user_id
    timestamps()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Imagine that we want to show all the users and their roles on an admin page:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;users = Repo.all(User)

users_with_roles =
  Enum.map(users, fn user -&amp;gt;
    role_assignments = Repo.all(from ra in MyApp.RoleAssignment, where: ra.user_id == ^user.id)
    roles = Enum.map(role_assignments, fn ra -&amp;gt; Repo.get!(MyApp.Role, ra.role_id) end)

    %{user | roles: roles}
  end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see here, we generate N queries to load the associated
roles for every user.&lt;/p&gt;
&lt;p&gt;To detect the N+1 query problem, you can use tools like
&lt;a href=&quot;https://hexdocs.pm/telemetry/readme.html&quot;&gt;Telemetry&lt;/a&gt;. Telemetry monitors query counts
and identifies queries that are executed multiple times with slight variations.&lt;/p&gt;
&lt;p&gt;For example, you wrap the query into a
&lt;a href=&quot;https://hexdocs.pm/telemetry/telemetry.html#span/3&quot;&gt;&lt;code&gt;span&lt;/code&gt;&lt;/a&gt; and then attach
a handler to the events to detect it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/user_context.ex
defmodule MyApp.UserContext do
  alias MyApp.User
  alias MyApp.Role
  alias MyApp.RoleAssignment

  alias MyApp.Repo

  def get_all_users do
    event = [:my_app, :query]                    # the name of the event
    start_metadata = %{context: &amp;quot;get_all_users&amp;quot;} # metadata to be sent on start

    :telemetry.span(event, start_metadata, fn -&amp;gt;
      users = Repo.all(User)
      result = Enum.map(users, fn user -&amp;gt;
        %{user | roles: get_roles(user)}
      end)

      stop_metadata = %{}                        # metadata to be sent on stop

      {result, stop_metadata}
    end)
  end

  def get_roles_for_user(user) do
    event = [:my_app, :query]                    # the name of the event
    start_metadata = %{                          # metadata to be sent on start
      context: &amp;quot;get_roles_for_user&amp;quot;,
      user_id: user.id
    }

    :telemetry.span(event, start_metadata, fn -&amp;gt;
      role_assignments = Repo.all(from ra in MyApp.RoleAssignment, where: ra.user_id == ^user.id)
      roles = Enum.map(role_assignments, fn ra -&amp;gt; Repo.get!(MyApp.Role, ra.role_id) end)

      stop_metadata = %{}                        # metadata to be sent on stop

      {roles, stop_metadata}
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We receive two events for every function call: one when the
span starts and the other when the span has finished.&lt;/p&gt;
&lt;p&gt;With the spans in place, we can now attach a handler to listen for any call to
them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Telemetry do
  # ...
  def handle_user_context_spans([:my_app, :user_repo, start_or_stop], _measurements, _metadata, _config) do

    case start_or_stop do
      :start -&amp;gt;
        # handle span start

      :stop -&amp;gt;
        # Record that a query was executed within the context
    end
  end
  #...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;New Phoenix applications ship with a telemetry supervisor under
&lt;code&gt;&amp;lt;app_web&amp;gt;/telemetry.ex&lt;/code&gt;. We can add the handler to its &lt;code&gt;init/1&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/my_app_web/telemetry.ex
defmodule MyAppWeb.Telemetry do
  # ...
  def init(_args) do
    children = [
      # ...
    ]

    :telemetry.attach_many(&amp;quot;user_context_handler&amp;quot;,
      [
        [:my_app, :user_repo, :start],
        [:my_app, :user_repo, :stop]
      ],
      &amp;amp;MyApp.Telemetry.handle_user_context_spans/4, [])

    Supervisor.init(children, strategy: :one_for_one)
  end
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here are a couple of strategies to detect N+1:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Count the total number of queries within a span context to analyze anomalies or spikes.&lt;/li&gt;
&lt;li&gt;Create a &lt;a href=&quot;https://hexdocs.pm/telemetry_metrics/Telemetry.Metrics.html&quot;&gt;metric&lt;/a&gt;, publish an event from the span handler, and, from there, plot data into a
dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is not an easy problem to spot, but when your application traffic starts to
increase, you&amp;#39;ll see some symptoms. Here are some additional things you
can look for that may indicate you&amp;#39;re experiencing an N+1 problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;High CPU usage on your database systems&lt;/li&gt;
&lt;li&gt;All the pages of your web app are fast &lt;em&gt;except&lt;/em&gt; for a few&lt;/li&gt;
&lt;li&gt;When you open them, lots of the same SQL is being executed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, the more instrumentation you have in place, the easier it is to
detect N+1 queries.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;For more information on N+1 queries and how to use AppSignal to detect them, read our post &lt;a href=&quot;https://blog.appsignal.com/2020/06/09/n-plus-one-queries-explained.html&quot;&gt;Performance and N+1 Queries: Explained, Spotted, and Solved&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Using Ecto&amp;#39;s Preload&lt;/h3&gt;
&lt;p&gt;Ecto provides the &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Query.html#preload/3&quot;&gt;&lt;code&gt;preload/3&lt;/code&gt;&lt;/a&gt;
function to load associated records in a single query, avoiding the N+1 query
problem.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of how to use &lt;code&gt;preload/3&lt;/code&gt;. First, add the proper relationship to the model:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/my_app/user.ex
defmodule MyApp.User do
  # ...

  schema &amp;quot;users&amp;quot; do
    # ...
    many_to_many :roles, MyApp.Role, join_through: MyApp.RoleAssignment
    # ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, to fetch all users along with their roles, you can use &lt;code&gt;preload/3&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Ecto.Query

users = MyApp.Repo.all(
  from(u in MyApp.User,
    preload: [:roles]
  )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will load the &lt;code&gt;user&lt;/code&gt; in one query, and &lt;code&gt;roles&lt;/code&gt; in another query,
regardless of the number of posts a user might have. Great — we go from
N+1 to 2!&lt;/p&gt;
&lt;p&gt;As an example, an N+1 query with 200 users and 200 roles takes 20 seconds
to load on my computer. Using the preload, this number is reduced to 600
milliseconds!&lt;/p&gt;
&lt;p&gt;But there is room for even more optimization.&lt;/p&gt;
&lt;h3&gt;Preloading with Joins&lt;/h3&gt;
&lt;p&gt;Preloading with joins has the advantage of generating only one query to load all
associated records from a database.&lt;/p&gt;
&lt;p&gt;In addition, you can also
filter or sort the associated records! Just use
&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Query.html#join/5&quot;&gt;&lt;code&gt;join/5&lt;/code&gt;&lt;/a&gt; along with
&lt;code&gt;preload/3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Following the same example from the last section:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Ecto.Query

query = from u in User,
  left_join: ra in assoc(u, :role_assignments),
  left_join: r in assoc(ra, :role),
  preload: [role_assignments: ra, roles: r],
  select: u

Repo.all(query)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This fetches users and their assigned roles using a single query, avoiding
the N+1 query problem. On my computer, this takes about 100 milliseconds to run.&lt;/p&gt;
&lt;p&gt;By leveraging Ecto&amp;#39;s &lt;code&gt;preload/3&lt;/code&gt; function and combining it with &lt;code&gt;join/5&lt;/code&gt; when
necessary, you can efficiently load associated records and eliminate the N+1
query problem in your Ecto-based applications.&lt;/p&gt;
&lt;h2&gt;Inefficient Queries in Ecto&lt;/h2&gt;
&lt;p&gt;Inefficient query execution can result in slow database performance, as poorly
designed queries may place unnecessary strain on the database. Now we&amp;#39;ll learn
how to detect and fix them.&lt;/p&gt;
&lt;h3&gt;Example 1: Missing Indexes&lt;/h3&gt;
&lt;p&gt;One of the most common causes of inefficient queries is a lack of indexes.&lt;/p&gt;
&lt;p&gt;Suppose we have a &lt;code&gt;Post&lt;/code&gt; schema like this one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/post.ex
defmodule MyApp.Role do
  use Ecto.Schema
  import Ecto.Changeset

  schema &amp;quot;posts&amp;quot; do
    field :title, :string
    field :body, :string

    field :published_at, Date

    timestamps()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s fetch all published posts ordered by their publication date:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Ecto.Query

published_posts = MyApp.Repo.all(
  from(p in MyApp.Post,
    where: is_nil(p.published_at) == false,
    order_by: [desc: p.published_at]
  )
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If there is no index on the &lt;code&gt;published_at&lt;/code&gt; field, this query may become slow
when the number of posts in the database grows. The database
system will perform a full scan of the table for every query.&lt;/p&gt;
&lt;p&gt;To fix this issue, you can add an index to the relevant column using a
migration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Repo.Migrations.AddIndexOnPublishedAt do
  use Ecto.Migration

  def change do
    create index(:posts, [:published_at])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;#39;s really no easy way to detect this from the application — it will
only start to be noticeable with queries on large tables. From the point of view
of an application, it&amp;#39;s only a slow query.&lt;/p&gt;
&lt;p&gt;In the next section, we&amp;#39;ll learn how to monitor the query execution time with
&lt;code&gt;telemetry&lt;/code&gt; to detect such problems.&lt;/p&gt;
&lt;h3&gt;Detecting Bad Queries with PostgreSQL and Telemetry&lt;/h3&gt;
&lt;p&gt;You can use tools like &lt;a href=&quot;https://www.postgresql.org/docs/current/sql-explain.html&quot;&gt;&lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;&lt;/a&gt; in
PostgreSQL (or similar features in other databases) to detect inefficient queries by analyzing the execution plan
and identifying possible bottlenecks.&lt;/p&gt;
&lt;p&gt;Additionally, you can use telemetry to monitor query execution times and set up
alerts if a query takes too long to execute.&lt;/p&gt;
&lt;p&gt;For example, you might &lt;a href=&quot;https://hexdocs.pm/telemetry/telemetry.html#attach/4&quot;&gt;add a handler&lt;/a&gt; to alert you if a
query takes longer than 5 seconds:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/my_app/telemetry.ex
defmodule MyApp.Telemetry do
  # ...
  def handle_event([:my_app, :repo, :query], measurements, metadata, _config) do
    query_time_ms = measurements[:query_time] / (1_000 * 1_000)
    if query_time_ms &amp;gt; 5_000 do
      # Send an alert or log a warning
    end
  end
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can attach the handler during the telemetry supervisor startup, just like
we did for the span handlers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/my_app_web/telemetry.ex
defmodule MyAppWeb.Telemetry do
  # ...
  def init(_args) do
    # ...

    :telemetry.attach(&amp;quot;query-time-handler&amp;quot;, [:my_app, :repo, :query], &amp;amp;MyApp.Telemetry.handle_event/4, [])

    Supervisor.init(children, strategy: :one_for_one)
  end
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Query timeouts can also serve as a bad smell, indicating that inefficient query
execution is occurring.&lt;/p&gt;
&lt;h2&gt;Ecto Connection Pooling and Concurrency Issues&lt;/h2&gt;
&lt;p&gt;Connection pooling problems can occur when an application tries to open more
connections to a database than the pool allows. This can lead to a bottleneck, as processes are left waiting in a &lt;strong&gt;queue&lt;/strong&gt; for an
available connection.&lt;/p&gt;
&lt;p&gt;Once again, telemetry can help us identify this problem. Ecto already ships with
Telemetry support and emits several events that we can listen to and react to.
&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#module-telemetry-events&quot;&gt;The documentation&lt;/a&gt;
has data and metadata that Ecto emits for all queries, including
&lt;em&gt;queue_time&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We can modify the previous handler example and also monitor long query
waiting times in the connection pool queue:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/my_app/telemetry.ex

  # ...
  def handle_event([:my_app, :repo, :query], measurements, metadata, _config) do
    queue_time_ms = measurements[:queue_time]

    if queue_time_ms &amp;gt; 5_000 do
      # The query waited more than 5s for a connection to be available
    end
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, you can always increase the number of connections in an application&amp;#39;s
configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/runtime.exs or config/dev.exs
config :hatch, MyApp.Repo,
  # ...
  pool_size: String.to_integer(System.get_env(&amp;quot;POOL_SIZE&amp;quot;, &amp;quot;10&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the config above, you can control the pool size using the &lt;code&gt;POOL_SIZE&lt;/code&gt; env
var or the default 10 connections size.&lt;/p&gt;
&lt;h2&gt;PostgreSQL Deadlocks&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.postgresql.org/docs/current/explicit-locking.html&quot;&gt;Locks&lt;/a&gt; are a
fundamental mechanism that databases use to ensure data integrity. Still, they can
struggle when there&amp;#39;s a high volume of updates from
different sources in the same timeframe.&lt;/p&gt;
&lt;p&gt;A deadlock occurs when two or more processes wait for each other to
release a resource, causing all processes to be stuck indefinitely.&lt;/p&gt;
&lt;h3&gt;How Deadlocks Occur&lt;/h3&gt;
&lt;p&gt;Deadlocks can happen when two or more processes try to acquire locks on multiple
resources in an inconsistent order.&lt;/p&gt;
&lt;p&gt;Consider the following schemas:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/lib/my_app/post.ex
defmodule MyApp.Post do
  use Ecto.Schema

  schema &amp;quot;posts&amp;quot; do
    field :reaction_count, :integer, default: 0
    has_many :reactions, MyApp.Reaction
  end
end

# my_app/lib/my_app/reaction.ex
defmodule MyApp.Reaction do
  use Ecto.Schema

  schema &amp;quot;reactions&amp;quot; do
    field :type, :string
    belongs_to :post, MyApp.Post
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now imagine the following scenario using post and reaction schemas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Process A acquires a lock on Post X.&lt;/li&gt;
&lt;li&gt;Process B acquires a lock on Post Y.&lt;/li&gt;
&lt;li&gt;Process A tries to acquire a lock on Post Y (but is blocked because Process B
holds the lock).&lt;/li&gt;
&lt;li&gt;Process B tries to acquire a lock on Post X (but is blocked because Process A
holds the lock).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case, both processes wait for each other to release the locks,
resulting in a deadlock.&lt;/p&gt;
&lt;p&gt;If two processes try to add reactions to different posts and update reaction counts at the same time, we could potentially run into a deadlock:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Process A
task_a = Task.async(fn -&amp;gt;
  Repo.transaction(fn -&amp;gt;
    post_x = Repo.lock!(from(p in Post, where: p.id == ^post_x_id))
    Repo.insert!(%Reaction{type: &amp;quot;like&amp;quot;, post_id: post_x.id})
    Repo.update!(Post.changeset(post_x, %{reaction_count: post_x.reaction_count + 1}))
  end)
end)

# Process B
task_b = Task.async(fn -&amp;gt;
  Repo.transaction(fn -&amp;gt;
    post_y = Repo.lock!(from(p in Post, where: p.id == ^post_y_id))
    Repo.insert!(%Reaction{type: &amp;quot;like&amp;quot;, post_id: post_y.id})
    Repo.update!(Post.changeset(post_y, %{reaction_count: post_y.reaction_count + 1}))
  end)
end)

Task.await(task_a)
Task.await(task_b)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most database systems provide mechanisms to detect and automatically
resolve deadlocks by rolling back one of the transactions involved.&lt;/p&gt;
&lt;p&gt;To prevent deadlocks, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Acquire locks in a consistent order across all processes. For example, you can
enforce ordering by post ID:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Repo.transaction(fn -&amp;gt;
  post = Repo.lock!(from(p in Post, where: p.id == ^post_id, order_by: :id))
  Repo.insert!(%Reaction{type: &amp;quot;like&amp;quot;, post_id: post.id})
  Repo.update!(Post.changeset(post, %{reaction_count: post.reaction_count + 1}))
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Use timeouts when acquiring locks to prevent indefinite waits. In Ecto, you can use the &lt;code&gt;:timeout&lt;/code&gt; option with the &lt;code&gt;Repo.transaction/2&lt;/code&gt; function:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Repo.transaction(fn -&amp;gt;
  post = Repo.lock!(from(p in Post, where: p.id == ^post_id))
  Repo.insert!(%Reaction{type: &amp;quot;like&amp;quot;, post_id: post.id})
  Repo.update!(Post.changeset(post, %{reaction_count: post.reaction_count + 1}))
end, timeout: 5_000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By setting a timeout, a transaction will be rolled back if it cannot acquire
the necessary locks within the specified time (preventing deadlocks from causing
an application to hang indefinitely).&lt;/p&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;From the application point of view, there is only so much that we can actually
monitor, since only a handful of entities can evaluate application
context like query execution time, queue time, memory consumption, etc.&lt;/p&gt;
&lt;p&gt;The best way
to know what is happening to your whole stack is to instrument your application with
tools like &lt;a href=&quot;https://hexdocs.pm/telemetry/readme.html&quot;&gt;Telemetry&lt;/a&gt; or
&lt;a href=&quot;https://opentelemetry.io/docs/instrumentation/erlang/&quot;&gt;OpenTelemetry&lt;/a&gt;, then
connect it to your favorite monitoring tool, like &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;AppSignal&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.appsignal.com/elixir/integrations/ecto.html&quot;&gt;Read more about instrumenting AppSignal for Ecto&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this article, we explored common performance issues in Elixir applications
using Ecto and provided insights on detecting and addressing these
problems.&lt;/p&gt;
&lt;p&gt;We started with the N+1 query problem, learning to identify and solve it using
Ecto&amp;#39;s preload functionality. Then we investigated inefficient query execution,
discussing how to optimize queries and use Telemetry for monitoring.&lt;/p&gt;
&lt;p&gt;Lastly, we covered connection pooling and concurrency issues, emphasizing the
importance of proper configuration, monitoring, and techniques for avoiding
deadlocks.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Absinthe</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/05/16/an-introduction-to-absinthe-for-elixir.html"/>
    <id>https://blog.appsignal.com/2023/05/16/an-introduction-to-absinthe-for-elixir.html</id>
    <published>2023-05-16T00:00:00+00:00</published>
    <updated>2023-05-16T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first part of this Absinthe for Elixir series, let&#039;s explore some of the basics of Absinthe and GraphQL.</summary>
    <content type="html">&lt;p&gt;Absinthe is a toolkit for building a GraphQL API with Elixir.
It has a declarative syntax that fits really well with Elixir’s idiomatic style.&lt;/p&gt;
&lt;p&gt;In today’s post — the first of a series on Absinthe — we will explore how you can use Absinthe to create a GraphQL API.&lt;/p&gt;
&lt;p&gt;But before we jump into Absinthe, let’s take a brief look at GraphQL.&lt;/p&gt;
&lt;h2&gt;GraphQL&lt;/h2&gt;
&lt;p&gt;GraphQL is a query language that allows declarative data fetching.
A client can ask for exactly what they want, and only that data is returned.&lt;/p&gt;
&lt;p&gt;Instead of having multiple endpoints like a REST API, a GraphQL API usually provides a single endpoint that can perform different operations based on the request body.&lt;/p&gt;
&lt;h3&gt;GraphQL Schema&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Schema&lt;/code&gt; forms the core of a GraphQL API.
In GraphQL, everything is strongly typed, and the schema contains information about the API&amp;#39;s capabilities.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take an example of a blog application. The schema can contain a &lt;code&gt;Post&lt;/code&gt; type like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;type Post {
  id: ID!
  title: String!
  body: String!
  author: Author!
  comments: [Comment]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above type specifies that a post will have an &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt; (all non-null because of &lt;code&gt;!&lt;/code&gt; in the type), and an optional (nullable) list of &lt;code&gt;comments&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&quot;https://graphql.org/learn/schema/&quot;&gt;Schema&lt;/a&gt; to learn about advanced concepts like &lt;code&gt;input&lt;/code&gt;, &lt;code&gt;Enum&lt;/code&gt;, and &lt;code&gt;Interface&lt;/code&gt;
in the type system.&lt;/p&gt;
&lt;h3&gt;GraphQL Query and Mutation&lt;/h3&gt;
&lt;p&gt;A type system is at the heart of the GraphQL schema.
GraphQL has two special types:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;query&lt;/code&gt; type that serves as an entry point for all read operations on the API.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;mutation&lt;/code&gt; type that exposes an API to mutate data on the server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each schema, therefore, has something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;schema {
  query: Query
  mutation: Mutation
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the &lt;code&gt;Query&lt;/code&gt; and &lt;code&gt;Mutation&lt;/code&gt; types provide the real API on the schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;type Query {
  post(id: ID!): Post
}

type Mutation {
  createPost(post: PostInput!): CreatePostResult!
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will get back to these types when we start creating our schema with Absinthe.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://graphql.org/learn/queries/&quot;&gt;Read more about GraphQL&amp;#39;s queries and mutations&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;GraphQL API&lt;/h3&gt;
&lt;p&gt;Clients can read the schema to know exactly what an API provides.
To perform queries (or mutations) on the API, you send a &lt;code&gt;document&lt;/code&gt; describing the operation to be performed. The server handles the rest and returns a result.
Let’s check out an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;query {
  post(id: 1) {
    id
    title
    author {
      id
      firstName
      lastName
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The response contains exactly what we&amp;#39;ve asked for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;data&amp;quot;: {
    &amp;quot;post&amp;quot;: {
      &amp;quot;id&amp;quot;: 1,
      &amp;quot;title&amp;quot;: &amp;quot;An Introduction to Absinthe&amp;quot;,
      &amp;quot;author&amp;quot;: {
        &amp;quot;id&amp;quot;: 1,
        &amp;quot;firstName&amp;quot;: &amp;quot;Sapan&amp;quot;,
        &amp;quot;lastName&amp;quot;: &amp;quot;Diwakar&amp;quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows for a more efficient data exchange compared to a REST API.
It&amp;#39;s especially useful for rarely used complex fields in a result that takes time to compute.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;In a REST API, such cases are usually handled by providing different endpoints for fetching that field or having special attributes like &lt;code&gt;include=complex_field&lt;/code&gt; in the query param.
On the other hand, a GraphQL API can offer native support by delaying the computation of that field unless it is explicitly asked for in the query.&lt;/p&gt;
&lt;h2&gt;Setting Up Your Elixir App with GraphQL and Absinthe&lt;/h2&gt;
&lt;p&gt;Let’s now turn to Absinthe and start building our API.
The installation is simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Add Absinthe, &lt;code&gt;Absinthe.Plug&lt;/code&gt;, and a JSON codec (like Jason) into your &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def deps do
  [
    # ...
    {:absinthe, &amp;quot;~&amp;gt; 1.7&amp;quot;},
    {:absinthe_plug, &amp;quot;~&amp;gt; 1.5&amp;quot;},
    {:jason, &amp;quot;~&amp;gt; 1.0&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add an entry in your router to forward requests to a specific path (e.g., &lt;code&gt;/api&lt;/code&gt;) to &lt;code&gt;Absinthe.Plug&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Router do
  use Phoenix.Router

  # ...

  forward &amp;quot;/api&amp;quot;, Absinthe.Plug, schema: MyAppWeb.Schema
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Absinthe.Plug&lt;/code&gt; will now handle all incoming requests to the &lt;code&gt;/api&lt;/code&gt; endpoint and forward them to &lt;code&gt;MyAppWeb.Schema&lt;/code&gt; (we will see how to write the schema below).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The installation steps might vary for different apps, so follow the &lt;a href=&quot;https://hexdocs.pm/absinthe/installation.html&quot;&gt;official Absinthe installation guide&lt;/a&gt; if you need more help.&lt;/p&gt;
&lt;h2&gt;Define the Absinthe Schema and Query&lt;/h2&gt;
&lt;p&gt;Notice that we&amp;#39;ve passed &lt;code&gt;MyAppWeb.Schema&lt;/code&gt; as the schema to &lt;code&gt;Absinthe.Plug&lt;/code&gt;.
This is the entry point of our GraphQL API.
To build it, we will use &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.html&quot;&gt;&lt;code&gt;Absinthe.Schema&lt;/code&gt;&lt;/a&gt; behaviour which provides macros for writing schema.
Let’s build the schema to support fetching a post by its id.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  query do
    field :post, :post do
      arg :id, non_null(:id)
      resolve fn %{id: post_id}, _ -&amp;gt;
        {:ok, MyApp.Blog.get_post!(post_id)}
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are a lot of things happening in the small snippet above.
Let’s break it down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We first define a &lt;code&gt;query&lt;/code&gt; block inside our schema.
This defines the special query type that we discussed in the GraphQL section.&lt;/li&gt;
&lt;li&gt;That &lt;code&gt;query&lt;/code&gt; type has only one field, named &lt;code&gt;post&lt;/code&gt;.
This is the first argument to the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#field/4&quot;&gt;&lt;code&gt;field&lt;/code&gt; macro&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The return type of the &lt;code&gt;post&lt;/code&gt; field is &lt;code&gt;post&lt;/code&gt; — this is the second argument to the macro.
We will get back to that later on.&lt;/li&gt;
&lt;li&gt;This field also has an argument named &lt;code&gt;id&lt;/code&gt;, defined using the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#arg/3&quot;&gt;&lt;code&gt;arg&lt;/code&gt; macro&lt;/a&gt;.
The type of that argument is &lt;code&gt;non_null(:id)&lt;/code&gt;, which is the Absinthe way of saying &lt;code&gt;ID!&lt;/code&gt; — a required value of type &lt;code&gt;ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally, the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#resolve/1&quot;&gt;&lt;code&gt;resolve&lt;/code&gt; macro&lt;/a&gt; defines how that field is resolved.
It accepts a 2-arity or 3-arity function that receives the parent entity (not passed for the 2-arity function), arguments map, and an &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Resolution.html&quot;&gt;Absinthe.Resolution&lt;/a&gt; struct.
The function&amp;#39;s return value should be &lt;code&gt;{:ok, value}&lt;/code&gt; or &lt;code&gt;{:error, reason}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Define the Type In Absinthe&lt;/h2&gt;
&lt;p&gt;In Absinthe, &lt;code&gt;object&lt;/code&gt; refers to any type that has sub-fields.
In the above query, we saw the type &lt;code&gt;post&lt;/code&gt;.
To create that type, we will use the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#object/3&quot;&gt;&lt;code&gt;object&lt;/code&gt; macro&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  @desc &amp;quot;A post&amp;quot;
  object :post do
    field :id, non_null(:id)
    field :title, non_null(:string)
    field :author, non_null(:author)
    field :comments, list_of(:comment)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first argument to the object macro is the identifier of the type.
This must be unique across the whole schema.
Each object can have many fields. Each field can use the full power of the &lt;code&gt;field&lt;/code&gt; macro that we saved above when defining the query. So we can define nested fields that accept arguments and return other &lt;code&gt;object&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;As we discussed earlier, the &lt;code&gt;query&lt;/code&gt; itself is an object, just a special one that serves as an entry point to the API.&lt;/p&gt;
&lt;h3&gt;Using Scalar Types&lt;/h3&gt;
&lt;p&gt;In addition to objects, you can also get &lt;code&gt;scalar&lt;/code&gt; types.
A scalar is a special type with no sub-fields and serializes to native values in the result (e.g.,
to a string).
A good example of a scalar is &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/DateTime.html&quot;&gt;Elixir’s &lt;code&gt;DateTime&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To support a &lt;code&gt;DateTime&lt;/code&gt; that we&amp;#39;ll use in the schema, we need to use the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#scalar/3&quot;&gt;&lt;code&gt;scalar&lt;/code&gt; macro&lt;/a&gt;. This tells Absinthe how to serialize and parse a &lt;code&gt;DateTime&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is an example from the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#scalar/3-examples&quot;&gt;Absinthe docs&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  scalar :isoz_datetime, description: &amp;quot;UTC only ISO8601 date time&amp;quot; do
    parse &amp;amp;Timex.parse(&amp;amp;1, &amp;quot;{ISO:Extended:Z}&amp;quot;)
    serialize &amp;amp;Timex.format!(&amp;amp;1, &amp;quot;{ISO:Extended:Z}&amp;quot;)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use this scalar anywhere in our schema by using &lt;code&gt;:isoz_datetime&lt;/code&gt; as the type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  @desc &amp;quot;A post&amp;quot;
  object :post do
    # ...
    field :created_at, non_null(:isoz_datetime)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Absinthe already provides several &lt;a href=&quot;https://hexdocs.pm/absinthe/1.1.5/Absinthe.Type.BuiltIns.html&quot;&gt;built-in scalars&lt;/a&gt; — &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;integer&lt;/code&gt;, and &lt;code&gt;string&lt;/code&gt; — as well as some &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Type.Custom.html&quot;&gt;custom scalars&lt;/a&gt;: &lt;code&gt;datetime&lt;/code&gt;, &lt;code&gt;naive_datetime&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, and &lt;code&gt;decimal&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Type Modifiers and More&lt;/h3&gt;
&lt;p&gt;We can also modify each type to mark some additional constraints or properties.
For example, to mark a type as non-null, we use the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#non_null/1&quot;&gt;&lt;code&gt;non_null/1&lt;/code&gt;&lt;/a&gt; macro.
To define a list of a specific type, we can use &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#list_of/1&quot;&gt;&lt;code&gt;list_of/1&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Advanced types like &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#union/3&quot;&gt;union&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#interface/3&quot;&gt;interface&lt;/a&gt; are also supported.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this post, we covered the basics of GraphQL and Absinthe for an Elixir application. We discussed the use of GraphQL and Absinthe schema, and touched on types in Absinthe.&lt;/p&gt;
&lt;p&gt;In the next part of this series, we&amp;#39;ll see how we can apply Absinthe and GraphQL to large Elixir applications.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Test Data Libraries for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/04/25/test-data-libraries-for-elixir.html"/>
    <id>https://blog.appsignal.com/2023/04/25/test-data-libraries-for-elixir.html</id>
    <published>2023-04-25T00:00:00+00:00</published>
    <updated>2023-04-25T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the final part of our testing data with Elixir series, we&#039;ll look at using test data libraries.</summary>
    <content type="html">&lt;p&gt;In part one of this series, we introduced Elixir test factories and fixtures. Then in part two, we explored using data generation functions.&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;ll look at some of the best Elixir libraries to use for your test data.&lt;/p&gt;
&lt;p&gt;But before we do, let&amp;#39;s quickly discuss why test data libraries can be helpful.&lt;/p&gt;
&lt;h2&gt;Why Choose a Test Data Library for Your Elixir App?&lt;/h2&gt;
&lt;p&gt;Elixir&amp;#39;s
built-in language features are more than sufficient for writing simple helpers to build
your application test data.&lt;/p&gt;
&lt;p&gt;For example, refer to the &lt;a href=&quot;https://hexdocs.pm/ecto/test-factories.html&quot;&gt;Ecto Guide&lt;/a&gt; to write a factory method pattern API like the one provided
by ExMachina.&lt;/p&gt;
&lt;p&gt;However, existing test data libraries are convenient as you don&amp;#39;t have to write them yourself.&lt;/p&gt;
&lt;h2&gt;Elixir Libraries for Your Test Data&lt;/h2&gt;
&lt;p&gt;Here&amp;#39;s a quick overview of existing test data
libraries and why you might want to use them. We&amp;#39;ll look at ExMachina, ExZample, Faker, and StreamData.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start with the most famous one: ExMachina.&lt;/p&gt;
&lt;h3&gt;ExMachina&lt;/h3&gt;
&lt;p&gt;The factory library &lt;a href=&quot;https://hex.pm/packages/ex_machina&quot;&gt;ExMachina&lt;/a&gt; created by &lt;a href=&quot;https://thoughtbot.com/&quot;&gt;Thoughbot&lt;/a&gt; uses function names and generates an atom used to call factories. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Factory do
  use ExMachina

  def github_repo_factory do
    repo_name = sequence(:github_repo_name, &amp;amp;&amp;quot;repo-#{1}&amp;quot;)

    %GitHub.Repo{
      id: 1296269,
      name: repo_name,
      full_name: &amp;quot;octocat/#{repo_name}&amp;quot;,
      description: &amp;quot;This your first repo!&amp;quot;,
      owner_id: 1,
      owner_url: &amp;quot;https://api.github.com/users/octocat&amp;quot;,
      private: false,
      html_url: &amp;quot;https://github.com/octocat/#{repo_name}&amp;quot;,
      url: &amp;quot;https://api.github.com/repos/octocat/#{repo_name}&amp;quot;
    }
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can invoke that factory using the functions provided by ExMachina. For
example, here&amp;#39;s a function that generates a list of resources:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;MyApp.Factory.build_list(3, :github_repo)
[
  %GitHub.Repo{
    name: &amp;quot;octocat/repo-1&amp;quot;
    # ...
  },
  %GitHub.Repo{
    name: &amp;quot;octocat/repo-2&amp;quot;
    # ...
  }
    %GitHub.Repo{
    name: &amp;quot;octocat/repo-3&amp;quot;
    # ...
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;github_repo_factory/0&lt;/code&gt; can be called using the &lt;code&gt;:github_repo&lt;/code&gt; atom, which can
call any utility function provided by ExMachina and injected by the &lt;code&gt;use ExMachina&lt;/code&gt;
macro.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;One of the most powerful features of &lt;code&gt;ExMachina&lt;/code&gt; is the &lt;code&gt;sequence&lt;/code&gt; function, which
guarantees you&amp;#39;ll get the next increment of a sequence each time you call it, and the
number will always be unique. It simplifies the caller&amp;#39;s job by eliminating the need
to explicitly pass a unique name. Using the sequence function automatically avoids unique
database constraint issues when calling the same factory multiple times.&lt;/p&gt;
&lt;p&gt;ExMachina also lets you add more building strategies, such as a JSON strategy that
transforms your data example into JSON. The documentation suggests that you create
smaller modules (with macros defining your factories) to break down a large factory module and
still serve everything under the same module API. However, I wouldn&amp;#39;t necessarily recommend
this approach: it&amp;#39;s harder to track the factory code definition if it breaks.
I would rather have multiple factory modules when using ExMachina.&lt;/p&gt;
&lt;p&gt;ExMachina is a well-established, actively maintained library that&amp;#39;s widely
used in the Elixir community. If invoking factories using the atom naming mechanism fits your preference,
it&amp;#39;s a solid choice!&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s take a look at another tool — ExZample.&lt;/p&gt;
&lt;h3&gt;ExZample&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ulissesalmeida/ex_zample&quot;&gt;ExZample&lt;/a&gt; is a factory library I wrote which allows you to use
defined examples in your struct modules. My goal was to enable
developers to organize their factories in any way they want while still
having access to convenient functions. For example, if you don&amp;#39;t define an example
function in &lt;code&gt;GitHub.Repo&lt;/code&gt;, you can still build the struct with its default values:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;ExZample.build_list(3, GitHub.Repo)
[
  %GitHub.Repo{
    name: nil
    # ...
  },
  %GitHub.Repo{
    name: nil
    # ...
  }
    %GitHub.Repo{
    name: nil
    # ...
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can define an &lt;code&gt;example&lt;/code&gt; function in the struct module, and ExZample will
automatically use it if it&amp;#39;s available.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# github/repo.ex
  def example do
    repo_name = sequence(:github_repo_name)

    %GitHub.Repo{
      id: 1296269,
      name: repo_name,
      full_name: &amp;quot;octocat/#{repo_name}&amp;quot;,
      description: &amp;quot;This your first repo!&amp;quot;,
      owner_id: 1,
      owner_url: &amp;quot;https://api.github.com/users/octocat&amp;quot;,
      private: false,
      html_url: &amp;quot;https://github.com/octocat/#{repo_name}&amp;quot;,
      url: &amp;quot;https://api.github.com/repos/octocat/#{repo_name}&amp;quot;
    }
  end

# test/support/test_helper.exs
# Sequences are created on app start
ExZample.create_sequence(:github_repo_name, &amp;amp;&amp;quot;repo-#{1}&amp;quot;)

# then you can invoke the data example with ExZample module:
ExZample.build_list(3, GitHub.Repo)
[
  %GitHub.Repo{
    name: &amp;quot;octocat/repo-1&amp;quot;
    # ...
  },
  %GitHub.Repo{
    name: &amp;quot;octocat/repo-1&amp;quot;
    # ...
  }
    %GitHub.Repo{
    name: &amp;quot;octocat/repo-1&amp;quot;
    # ...
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you prefer the atom naming mechanism of ExMachina, &lt;code&gt;ExZample.DSL&lt;/code&gt; has you covered.
You can define your factory in a module like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Factory do
  use ExZample.DSL

  factory :github_repo do
    example do
      repo_name = sequence(:github_repo_name)
      %GitHub.Repo{
        id: 1296269,
        name: repo_name,
        full_name: &amp;quot;octocat/#{repo_name}&amp;quot;,
        description: &amp;quot;This your first repo!&amp;quot;,
        owner_id: 1,
        owner_url: &amp;quot;https://api.github.com/users/octocat&amp;quot;,
        private: false,
        html_url: &amp;quot;https://github.com/octocat/#{repo_name}&amp;quot;,
        url: &amp;quot;https://api.github.com/repos/octocat/#{repo_name}&amp;quot;
      }
    end
  end

  def_sequence :github_repo_name, return: &amp;amp;&amp;quot;repo-#{1}&amp;quot;
end

# Then use the aliased factory in your tests:
ExZample.build_list(3, :github_repo)
[
  %GitHub.Repo{
    name: &amp;quot;octocat/repo-1&amp;quot;
    # ...
  },
  %GitHub.Repo{
    name: &amp;quot;octocat/repo-1&amp;quot;
    # ...
  }
    %GitHub.Repo{
    name: &amp;quot;octocat/repo-1&amp;quot;
    # ...
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use macros provided by &lt;code&gt;ExZample.DSL&lt;/code&gt; to define
factories using the &lt;code&gt;factory&lt;/code&gt; directive. We need to explicitly define the atom
name &lt;code&gt;:github_repo&lt;/code&gt;. Inside the &lt;code&gt;factory&lt;/code&gt; body, we define the &lt;code&gt;example&lt;/code&gt; block
that builds a struct example.&lt;/p&gt;
&lt;p&gt;Although the ExZample library may not be as well-known or extensively tested as
ExMachina, ExZample was designed to pick up the exact features you need
and ignore the rest. You may want to consider giving it a try. If you have any feedback
or suggestions for improvements, &lt;a href=&quot;https://github.com/ulissesalmeida/ex_zample/issues&quot;&gt;feel free to contribute&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next up, let&amp;#39;s see what Faker has to offer.&lt;/p&gt;
&lt;h3&gt;Faker&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elixirs/faker&quot;&gt;Faker&lt;/a&gt; generates sample data that looks realistic but is
fake. So, instead of using a &lt;code&gt;sequence&lt;/code&gt; like those provided by ExMachina or ExZample,
we can use &lt;code&gt;Faker&lt;/code&gt; to generate false but genuine-looking data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/support/test_helper.exs
# Ensure you start Faker before running your tests
Faker.start()

Faker.Internet.slug()
&amp;quot;sit_et&amp;quot;

Faker.Internet.slug()
&amp;quot;deleniti-consequatur&amp;quot;

Faker.Internet.slug()
&amp;quot;foo-bar&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The random nature of data generation can sometimes result
in duplicate names, which may cause flaky tests. However, this is
likely to occur only in rare situations, so it&amp;#39;s still worth relying
on Faker. Faker has an impressive collection of data samples and generation
algorithms, including IP addresses, e-mails, URLs, addresses, and even
Pokémon names. It&amp;#39;s a great library to use in combination with the others
presented here.&lt;/p&gt;
&lt;p&gt;Finally, let&amp;#39;s take a quick look at StreamData.&lt;/p&gt;
&lt;h3&gt;StreamData&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/stream_data/StreamData.html&quot;&gt;&lt;code&gt;StreamData&lt;/code&gt;&lt;/a&gt; generates a bunch of data
samples for you. Unlike Faker, StreamData doesn&amp;#39;t aim to generate realistic values. It creates
raw, random data. You ask for a raw data type, and you get it. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Enum.take(StreamData.string(:alphanumeric), 3)
#=&amp;gt; [&amp;quot;AcT&amp;quot;, &amp;quot;9Ac&amp;quot;, &amp;quot;TxY&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;StreamData&lt;/code&gt; returns a data generator that produces an infinite amount of random data. It
implements the &lt;code&gt;Enumerable&lt;/code&gt; protocol, so you can filter data using the
&lt;code&gt;Enum&lt;/code&gt; functions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;StreamData.string(:alphanumeric)
|&amp;gt; Enum.filter(&amp;amp;(String.length(&amp;amp;1) &amp;gt;= 5 and String.length(&amp;amp;1) &amp;lt;= 10))
|&amp;gt; Enum.take(1)
[&amp;quot;hygT78ch&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, we&amp;#39;re only interested in grabbing strings between 5 and 10
characters long. &lt;code&gt;StreamData&lt;/code&gt; was designed to be used with &lt;a href=&quot;https://elixir-lang.org/blog/2017/10/31/stream-data-property-based-testing-and-data-generation-for-elixir/&quot;&gt;property testing&lt;/a&gt;,
but you can also use its powerful data samples to build data examples for regular
tests.&lt;/p&gt;
&lt;h2&gt;General Thoughts and Suggestions&lt;/h2&gt;
&lt;p&gt;I often wonder if it&amp;#39;s
worth deviating too far from the Elixir standard library when using a
certain pattern. So I would like to invite
you to aim for the following in your next Elixir project:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Try using your application&amp;#39;s functions and rules to build test data. Create wrappers to simplify their usage if needed, with convenient defaults for testing.&lt;/li&gt;
&lt;li&gt;When your application doesn&amp;#39;t control the accuracy of your data, try to create &lt;code&gt;example&lt;/code&gt;
functions on the struct modules and use them to test your code.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Faker&lt;/code&gt; or &lt;code&gt;StreamData&lt;/code&gt; to add some randomness, enriching your test data and
making your tests less dependent on specific data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If these three points still aren&amp;#39;t enough for your data testing needs, embrace a factory library to bring more convenience and structure to your test
suite.&lt;/p&gt;
&lt;p&gt;If you try the lean suggested approaches, you might realize how little you
really need to be able to generate test data and have a healthy test suite.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In part one of this series, we summarised the ins and outs of Elixir test factories and fixtures. In the second part, we focused on generating data functions.&lt;/p&gt;
&lt;p&gt;Finally, in this third and last part, we explored some test data libraries you can use for your Elixir application, including ExMachina, ExZample, Faker, and StreamData.&lt;/p&gt;
&lt;p&gt;I hope you found this series helpful.&lt;/p&gt;
&lt;p&gt;Good luck with your testing!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Mocking Tools for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/04/11/an-introduction-to-mocking-tools-for-elixir.html"/>
    <id>https://blog.appsignal.com/2023/04/11/an-introduction-to-mocking-tools-for-elixir.html</id>
    <published>2023-04-11T00:00:00+00:00</published>
    <updated>2023-04-11T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s explore three mocking tools you can use in Elixir — Mock, Mox, and Mimic.</summary>
    <content type="html">&lt;p&gt;A well-written test suite is a big part of any successful application.
But let&amp;#39;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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GithubAPI do
  def fetch_user(username) do
    case HTTPoison.get(&amp;quot;https://api.github.com/users/#{username}&amp;quot;) do
      {:ok, response} -&amp;gt;
        parse(response)
      {:error, reason} -&amp;gt;
        {:error, reason}
    end
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GithubAPI do
  def fetch_user(username, http_client \\ HTTPoison) do
    case http_client.get(&amp;quot;https://api.github.com/users/#{username}&amp;quot;) do
      #... handle results
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach aligns with the &lt;a href=&quot;https://www.infoworld.com/article/3136224/demystifying-the-law-of-demeter-principle.html&quot;&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.
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.
For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GithubAPITest do
  defmodule GithubHTTPClientUser do
    def get(&amp;quot;https://api.github.com/users/octocat&amp;quot;) do
      {:ok, %HTTPoison.Response{status_code: 200, body: ~s&amp;lt;{&amp;quot;login&amp;quot;: &amp;quot;octocat&amp;quot;}&amp;gt;}}
    end
    def get(&amp;quot;https://api.github.com/users/unknown&amp;quot;) do
      {:error, %HTTPoison.Error{message: &amp;quot;Not Found&amp;quot;}}
    end
  end

  test &amp;quot;can fetch a user&amp;quot; do
    {:ok, %Github.User{login: &amp;quot;octocat&amp;quot;}} = GithubAPI.fetch_user(&amp;quot;octocat&amp;quot;, GithubHTTPClientUser)
  end

  test &amp;quot;handles errors when fetching a user&amp;quot; do
    {:error, %HTTPoison.Error{}} = GithubAPI.fetch_user(&amp;quot;unknown&amp;quot;, GithubHTTPClientUser)
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# github_api.ex
defmodule GithubAPI do
  @http_client Application.compile_env(:my_app, GithubAPI, []) |&amp;gt; Keyword.get(:http_client, HTTPoison)

  def fetch_user(username) do
    case @http_client.get(&amp;quot;https://api.github.com/users/#{username}&amp;quot;) do
      #... handle results
    end
  end
end

# test/support/mock_github_http_client.ex
defmodule MockGithubHTTPClient do
    # ... All mock implementations here
end

# config/test.exs
config :my_app, GithubAPI, http_client: MockGithubHTTPClient
&lt;/code&gt;&lt;/pre&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.
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=&quot;https://github.com/elixir-plug/plug_cowboy&quot;&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;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;If you want to learn more, check out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/flatiron-labs/rolling-your-own-mock-server-for-testing-in-elixir-2cdb5ccdd1a0&quot;&gt;Testing External Web Requests in Elixir? Roll Your Own Mock Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.appsignal.com/2021/06/22/how-to-test-websocket-clients-in-elixir-with-a-mock-server.html&quot;&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.
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=&quot;https://github.com/jjh42/mock&quot;&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=&quot;https://github.com/eproxus/meck&quot;&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=&quot;https://github.com/jjh42/mock#with_mock---Mocking-a-single-module&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GithubAPITest do
  # This is important, Mock doesn&amp;#39;t work with async tests!
  use ExUnit.Case, async: false

  import Mock

  test &amp;quot;can fetch a user&amp;quot; do
    with_mock HTTPoison, [get: fn _url -&amp;gt; {:ok, %{status_code: 200, body: ~s({&amp;quot;login&amp;quot;: &amp;quot;octocat&amp;quot;})}} end] do
      {:ok, %Github.User{login: &amp;quot;octocat&amp;quot;}} = GithubAPI.fetch_user(&amp;quot;octocat&amp;quot;)
      assert_called HTTPotion.get(&amp;quot;https://api.github.com/users/octocat&amp;quot;)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Very sleek. There&amp;#39;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.
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=&quot;https://github.com/edgurgel/tentacat&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def create_user(github_username) do
  Tentacat.Users.find(Tentacat.Client.new(), github_username)
  |&amp;gt; case do
    {:ok, user} -&amp;gt;
      # ... create user
    {:error, error} -&amp;gt;
      # ... handle error
  end
end
&lt;/code&gt;&lt;/pre&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&amp;#39;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.
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.
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=&quot;https://github.com/dashbitco/mox&quot;&gt;Mox&lt;/a&gt; helps get around these issues by ensuring explicit contracts.
Read &lt;a href=&quot;https://dashbit.co/blog/mocks-and-explicit-contracts&quot;&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=&quot;https://hexdocs.pm/elixir/1.4.5/behaviours.html&quot;&gt;&lt;code&gt;Behaviour&lt;/code&gt;&lt;/a&gt; to define the explicit contract the API client should follow.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app/github/api.ex
defmodule MyApp.GithubAPI do
  @callback fetch_user(String.t()) :: {:ok, Github.User.t()} | {:error, Github.Error.t()}

  def fetch_user(username), do: impl().fetch_user(username) do

  defp impl(), do: Application.get_env(:my_app, GithubAPI, GtihubAPI.HTTP)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we define the API Client that makes the actual request to fetch the user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app/github/http.ex
defmodule MyApp.GithubAPI.HTTP do
  @behaviour MyApp.GithubAPI

  @impl true
  def fetch_user(username) do
    case HTTPoison.get(&amp;quot;https://api.github.com/users/#{username}&amp;quot;) do
      {:ok, response} -&amp;gt;
        # Parse response here...
        {:ok, user}
      {:error, error} -&amp;gt;
        # Handle error here...
        {:error, reason}
    end
  end
end
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/test_helper.exs
Mox.defmock(MyApp.GithubAPI.Mock, for: MyApp.GithubAPI)
Application.put_env(:my_app, GithubAPI, MyApp.GithubAPI.Mock)
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/my_app/github/api_test.exs
defmodule GithubAPITest do
  use ExUnit.Case, async: true

  import Mox

  setup :verify_on_exit!

  test &amp;quot;can fetch a user&amp;quot; do
    MyApp.GithubAPI.Mock
    |&amp;gt; expect(:fetch_user, fn &amp;quot;octocat&amp;quot; -&amp;gt; {:ok, %Github.User{login: &amp;quot;octocat&amp;quot;}} end)
    assert {:ok, %Github.User{login: &amp;quot;octocat&amp;quot;}} = GithubAPI.fetch_user(&amp;quot;octocat&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are several interesting aspects to the above code. Let&amp;#39;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;&amp;quot;octocat&amp;quot;&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&amp;#39;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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Case do
  use ExUnit.CaseTemplate

  setup _context do
    Mox.stub_with(MyApp.GithubAPI.Mock, MyApp.GithubAPI.Stub)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And create a stub with some static results:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.GithubAPI.Stub do
  @behaviour MyApp.GithubAPI

  @impl true
  def fetch_user(&amp;quot;octocat&amp;quot;), do: {:ok, %Github.User{login: &amp;quot;octocat&amp;quot;}}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now every time you &lt;code&gt;use MyApp.Case&lt;/code&gt; in a test case, you don&amp;#39;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.
Don’t worry, we won’t leave it untested.
But the recommended way here is to do integration tests instead of using mocking at that level.
We will also configure it so that these tests don’t run when you run the full test suite.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/my_app/github/http_test.exs
defmodule MyApp.GithubAPI.HTTPTest do
  use ExUnit.Case, async: true

  # All tests will ping the API
  @moduletag :github_api

  # Write your tests here
end

# test/test_helper.exs
ExUnit.configure exclude: [:github_api]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to set up your CI pipeline to ensure that these tests run when required.
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.
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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;mix test --include github_api
&lt;/code&gt;&lt;/pre&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&amp;#39;s availability.&lt;/p&gt;
&lt;h2&gt;Mimic&lt;/h2&gt;
&lt;p&gt;If you are used to &lt;a href=&quot;https://github.com/freerange/mocha&quot;&gt;Mocha&lt;/a&gt; for other languages, you can check out &lt;a href=&quot;https://github.com/edgurgel/mimic&quot;&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.
It also maintains separate mocks for each process, so you can continue using async tests.
It’s a great alternative to &lt;a href=&quot;https://github.com/jjh42/mock&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test_helper.exs
Mmimc.copy(HTTPoison)
ExUnit.start()

# github_api_test.exs
defmodule GithubAPITest do
  use ExUnit.Case, async: true
  use Mimic

  test &amp;quot;can fetch a user&amp;quot; do
    url = &amp;quot;https://api.github.com/users/octocat&amp;quot;
    expect(HTTPoison, :get, fn ^url -&amp;gt; {:ok, %{status_code: 200, body: ~s({&amp;quot;login&amp;quot;: &amp;quot;octocat&amp;quot;})}} end)
    assert {:ok, %Github.User{login: &amp;quot;octocat&amp;quot;}} = GithubAPI.fetch_user(&amp;quot;octocat&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;expect/3&lt;/code&gt; automatically verifies that the function is called.
And all &lt;code&gt;expect&lt;/code&gt; and &lt;code&gt;stub&lt;/code&gt; calls can be &lt;a href=&quot;https://github.com/edgurgel/mimic#using&quot;&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.
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&amp;#39;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&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Debugging Phoenix LiveView with open_browser/2</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/03/28/debugging-phoenix-liveview-with-open-browser2.html"/>
    <id>https://blog.appsignal.com/2023/03/28/debugging-phoenix-liveview-with-open-browser2.html</id>
    <published>2023-03-28T00:00:00+00:00</published>
    <updated>2023-03-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how to debug Phoenix LiveView tests with open_browser/2.</summary>
    <content type="html">&lt;p&gt;In this blog post, you&amp;#39;ll see how useful &lt;code&gt;open_browser/2&lt;/code&gt; is when debugging LiveView tests. In addition, we&amp;#39;ll give a brief introduction to testing LiveView.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Introducing LiveView Testing&lt;/h2&gt;
&lt;p&gt;Testing during the software development process is one way to build confidence and ensure your application will work as expected.&lt;/p&gt;
&lt;p&gt;The ability to easily write meaningful tests is an important factor for any framework, regardless of programming language.&lt;/p&gt;
&lt;p&gt;Developers can easily test the LiveView framework&amp;#39;s component, life-cycle, and behavior by writing LiveView tests with pure Elixir, since it uses ExUnit (a built-in testing framework) for all its testing. We can be confident in writing LiveView tests that are fast, concurrent, and stable.&lt;/p&gt;
&lt;p&gt;You can test the functionality of your live views&amp;#39; behavior through the help of the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html#content&quot;&gt;&lt;code&gt;Phoenix.LiveViewTest&lt;/code&gt;&lt;/a&gt; module, which offers convenient functions without the need to introduce JS testing frameworks. The test helpers assist us in writing meaningful tests for our LiveView modules with ease and speed.&lt;/p&gt;
&lt;h2&gt;Sample Feature in LiveView&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s write a sample feature to use as our testing example.&lt;/p&gt;
&lt;p&gt;We shall add a form to our application that allows users to enter their email address and password when attempting to register. This feature will only focus on the rendered HTML and not include the ability to add users into the system (the backend part of taking user params and adding them into the data store).&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s begin!&lt;/p&gt;
&lt;p&gt;First, start by creating a new LiveView application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix phx.new sample_live --live
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NB: You can use an existing LiveView application if you have one.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;mix phx.new&lt;/code&gt; command with the &lt;code&gt;--live&lt;/code&gt; flag will create a new application with LiveView installed and configured.&lt;/p&gt;
&lt;p&gt;Add a live path in the router.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/sample_live_web/router.ex

scope &amp;quot;/&amp;quot;, SampleLiveWeb do

  live &amp;quot;/user_registration&amp;quot;, RegistrationLive

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create &lt;code&gt;registration_live.ex&lt;/code&gt; inside the &lt;code&gt;sample_live_web&lt;/code&gt; folder.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/sample_live_web/registration_live.ex

defmodule SampleLiveWeb.RegistrationLive do

  use SampleLiveWeb, :live_view


  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;

      &amp;lt;.form let={f} for={:changeset} id={&amp;quot;registration-form&amp;quot;} &amp;gt;

        &amp;lt;%= label f, :email %&amp;gt;
        &amp;lt;%= text_input f, :email, id: &amp;quot;email-input&amp;quot; %&amp;gt;
        &amp;lt;%= error_tag f, :email %&amp;gt;
        &amp;lt;%= label f, :password, id: &amp;quot;password-input&amp;quot; %&amp;gt;
        &amp;lt;%= password_input f, :password %&amp;gt;
        &amp;lt;%= error_tag f, :password %&amp;gt;
        &amp;lt;%= submit &amp;quot;Save&amp;quot; %&amp;gt;
      &amp;lt;/.form&amp;gt;

    &amp;quot;&amp;quot;&amp;quot;
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our LiveView application module, two callbacks have been defined: &lt;code&gt;mount/3&lt;/code&gt; and &lt;code&gt;render/1&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The &lt;code&gt;mount/3&lt;/code&gt; callback expects three arguments — &lt;code&gt;params&lt;/code&gt;, &lt;code&gt;session&lt;/code&gt;, and &lt;code&gt;liveview socket&lt;/code&gt; — and returns &lt;code&gt;{:ok, socket}&lt;/code&gt;. When the LiveView page is rendered, the &lt;code&gt;mount/3&lt;/code&gt; callback will be invoked twice: once to perform the initial page load and again to establish the live connection.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;render/1&lt;/code&gt; callback is responsible for displaying the &lt;code&gt;HTML&lt;/code&gt; template/content — in this case, the added registration form. It receives the &lt;code&gt;socket assigns&lt;/code&gt; and must return a template passed inside the &lt;code&gt;~H sigil&lt;/code&gt;. Whenever there is a change in our LiveView, the &lt;code&gt;render/1&lt;/code&gt; callback will be invoked.&lt;/p&gt;
&lt;p&gt;In our template, we have defined a sample form where a user can enter their email and password.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start the server and open the registration form in our browsers. You should see something similar to this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-03/registration-page.png&quot; alt=&quot;registration_page&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Display the Feature on the Browser while Testing&lt;/h2&gt;
&lt;p&gt;When working on an HTTP-based web application, we usually write integration tests to validate passing expected attributes and properties to parts of our application.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll write an integration test validating user interactions with our application. The test should verify that when a user visits the &lt;code&gt;/user_registration&lt;/code&gt; page, they can see the registration form properties/attributes rendered. In addition, we&amp;#39;ll explore how we can use &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html#open_browser/2&quot;&gt;open_browser/2&lt;/a&gt; to debug our LiveView test.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s write a test for our form implemented above that will verify the HTML rendered. In here, we shall use &lt;code&gt;open_browser/2&lt;/code&gt; to verify the displayed form. The implemented registration form has an HTML &lt;code&gt;id&lt;/code&gt; (&lt;code&gt;&amp;quot;registration-form&amp;quot;&lt;/code&gt;) that should help us select the element in our test.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/sample_live_web/registration_live_test.exs

defmodule SampleLiveWeb.RegistrationLiveTest do
  use SamplLiveWeb.ConnCase
  import Phoenix.LiveViewTest

  test &amp;quot;user can see registration form&amp;quot;, %{conn: conn} do
    {:ok, view, html} = live(conn, &amp;quot;/user_registration&amp;quot;)

    html =
      view
      |&amp;gt; element(&amp;quot;#registration-form&amp;quot;)
      |&amp;gt; open_browser()
      |&amp;gt; render()

    assert html =~ &amp;quot;Email&amp;lt;/label&amp;gt;&amp;quot;
    assert html =~ &amp;quot;Password&amp;lt;/label&amp;gt;&amp;quot;

  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import Phoenix.LiveViewTest&lt;/code&gt; module gets access to the test helper functions.&lt;/p&gt;
&lt;p&gt;In the sample feature, when a user is on the application and wants to visit the registration page, they will navigate to &lt;code&gt;/user_registration&lt;/code&gt;. A similar thing happens here — we shall navigate the user to &lt;code&gt;/user_registration&lt;/code&gt; using &lt;code&gt;live/2&lt;/code&gt;, which performs a regular &lt;code&gt;get(conn, path)&lt;/code&gt; and then upgrades the page to LiveView. It takes in the &lt;code&gt;conn&lt;/code&gt; and the &lt;code&gt;path&lt;/code&gt; then returns a three-element tuple with &lt;code&gt;:ok&lt;/code&gt;, &lt;code&gt;liveview process&lt;/code&gt;, and the &lt;code&gt;rendered HTML&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;open_browser/2&lt;/code&gt; expects a &lt;code&gt;view&lt;/code&gt; or &lt;code&gt;element&lt;/code&gt; as the first argument. In the test, I have opted to pass an element, and this can be done by invoking &lt;code&gt;element/3&lt;/code&gt;, passing the &lt;code&gt;view&lt;/code&gt; and the &lt;code&gt;query selector&lt;/code&gt; to it. &lt;code&gt;element/3&lt;/code&gt; returns an &lt;code&gt;element&lt;/code&gt; which is then passed to &lt;code&gt;open_browser/2&lt;/code&gt;. If &lt;code&gt;open_browser/2&lt;/code&gt; finds the form element with the &lt;code&gt;query selector&lt;/code&gt;(#registration-form) within the LiveView page, we expect the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The default browser to be opened displaying the HTML of the form element.&lt;/li&gt;
&lt;li&gt;The form element to be returned.
The &lt;code&gt;form element&lt;/code&gt; returned can be passed to &lt;code&gt;render/1&lt;/code&gt;, which takes in a &lt;code&gt;view_or_element&lt;/code&gt; and returns an HTML string of the view that we can finally assert in the test.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Run the test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix test test/sampl_live_web/registration_live_test.exs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We should expect the default browser to open and our test to pass.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-03/registration-page-open-browser.png&quot; alt=&quot;registration page opened by open_browser&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Now, let&amp;#39;s make the user enter their email and password by using &lt;code&gt;form/3&lt;/code&gt;, which takes in the &lt;code&gt;view&lt;/code&gt;, &lt;code&gt;query selector&lt;/code&gt;, and &lt;code&gt;form data&lt;/code&gt;, and then returns a form element. But this time we&amp;#39;ll use a query selector that doesn&amp;#39;t exist to demonstrate how &lt;code&gt;open_browser/2&lt;/code&gt; can be useful in debugging LiveView tests.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/sample_live_web/registration_live_test.exs

defmodule SampleLiveWeb.RegistrationLiveTest do
  use SamplLiveWeb.ConnCase
  import Phoenix.LiveViewTest

  test &amp;quot;user can see registration form&amp;quot;, %{conn: conn} do
    {:ok, view, html} = live(conn, &amp;quot;/user_registration&amp;quot;)

    view
    |&amp;gt; element(&amp;quot;#registration-form&amp;quot;)
    |&amp;gt; open_browser()

    view
    |&amp;gt; form(&amp;quot;#wrong_registration-form&amp;quot;, user: %{email: &amp;quot;hello@email.com&amp;quot;, password: &amp;quot;hello123&amp;quot;})
    |&amp;gt; render()

  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s run the test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;** (ArgumentError) expected selector &amp;quot;#wrong_registration-form&amp;quot; to return a single element, but got none within:

&amp;lt;main class=&amp;quot;container&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;alert alert-info&amp;quot; role=&amp;quot;alert&amp;quot; phx-click=&amp;quot;lv:clear-flash&amp;quot; phx-value-key=&amp;quot;info&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p class=&amp;quot;alert alert-danger&amp;quot; role=&amp;quot;alert&amp;quot; phx-click=&amp;quot;lv:clear-flash&amp;quot; phx-value-key=&amp;quot;error&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;form action=&amp;quot;#&amp;quot; method=&amp;quot;post&amp;quot; id=&amp;quot;registration-form&amp;quot; phx-submit=&amp;quot;save&amp;quot;&amp;gt;&amp;lt;input name=&amp;quot;_csrf_token&amp;quot; type=&amp;quot;hidden&amp;quot; value=&amp;quot;CHwQRnBHAnF7JDQEXQk3AXx8QQ0hZxceYLY-91nA2PLS3bB13Q0HC8CQ&amp;quot;/&amp;gt;&amp;lt;label for=&amp;quot;registration-form_email&amp;quot;&amp;gt;Email&amp;lt;/label&amp;gt;&amp;lt;input id=&amp;quot;email-input&amp;quot; name=&amp;quot;user[email]&amp;quot; type=&amp;quot;text&amp;quot;/&amp;gt;&amp;lt;label for=&amp;quot;registration-form_password&amp;quot;&amp;gt;Password&amp;lt;/label&amp;gt;&amp;lt;input id=&amp;quot;password-input&amp;quot; name=&amp;quot;user[password]&amp;quot; type=&amp;quot;password&amp;quot;/&amp;gt;&amp;lt;button type=&amp;quot;submit&amp;quot;&amp;gt;Save&amp;lt;/button&amp;gt;&amp;lt;/form&amp;gt;&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We notice that our test is failing with an &lt;code&gt;ArgumentError&lt;/code&gt;. In this test, the &lt;code&gt;form/3&lt;/code&gt; function returns a &lt;code&gt;form element&lt;/code&gt; with the query selector &lt;code&gt;#wrong_registration-form&lt;/code&gt;. This &lt;code&gt;form element&lt;/code&gt; is then passed to &lt;code&gt;render/1&lt;/code&gt;, which expects the &lt;code&gt;form element&lt;/code&gt; with the query selector &lt;code&gt;#wrong_registration-form&lt;/code&gt; passed to it as the first argument to return a form element (but it gets none within the LiveView page). The test has made it clear that we are using the wrong query selector.&lt;/p&gt;
&lt;p&gt;Our form template is very short, so it&amp;#39;s easy to identify our mistake. Even from the HTML string displayed on the terminal after running the test, it&amp;#39;s easy to point out the query selector we should have used.&lt;/p&gt;
&lt;p&gt;Imagine working with larger HTML templates, though. It will be cumbersome to go through the HTML string to try and identify the mistake. Let&amp;#39;s examine how &lt;code&gt;open_browser/2&lt;/code&gt; can come in handy in that case.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s add &lt;code&gt;open_browser/2&lt;/code&gt; after &lt;code&gt;form/3&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/sample_live_web/registration_live_test.exs

defmodule SampleLiveWeb.RegistrationLiveTest do
  use SamplLiveWeb.ConnCase
  import Phoenix.LiveViewTest

  test &amp;quot;user can see registration form&amp;quot;, %{conn: conn} do
    {:ok, view, html} = live(conn, &amp;quot;/user_registration&amp;quot;)

    view
    |&amp;gt; element(&amp;quot;#registration-form&amp;quot;)
    |&amp;gt; open_browser()

    view
    |&amp;gt; form(&amp;quot;#wrong_registration-form&amp;quot;, user: %{email: &amp;quot;hello@email.com&amp;quot;, password: &amp;quot;hello123&amp;quot;})
    |&amp;gt; open_browser()
    |&amp;gt; render()

  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, we expect the browser to open with the displayed registration form — but apparently, that won&amp;#39;t be the case when we run our test. Just like the &lt;code&gt;render/1&lt;/code&gt; function, &lt;code&gt;open_browser/2&lt;/code&gt; expects the &lt;code&gt;form element&lt;/code&gt; with the query selector &lt;code&gt;#wrong_registration-form&lt;/code&gt; passed to it, but it doesn&amp;#39;t exist.&lt;/p&gt;
&lt;p&gt;The other option is to debug the LiveView page where the registration form is rendered. In the test, we shall call &lt;code&gt;open_browser/2&lt;/code&gt; and pass the &lt;code&gt;view&lt;/code&gt; returned after invoking &lt;code&gt;live/2&lt;/code&gt; to it. Earlier on, I mentioned that &lt;code&gt;open_browser/2&lt;/code&gt; could either take in a &lt;code&gt;view&lt;/code&gt; or an &lt;code&gt;element&lt;/code&gt;. The option to use an &lt;code&gt;element&lt;/code&gt; is failing due to the wrong &lt;code&gt;query selector&lt;/code&gt;. So using &lt;code&gt;view&lt;/code&gt; can be a better option in our case to help us understand why the test is failing.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/sample_live_web/registration_live_test.exs

defmodule SampleLiveWeb.RegistrationLiveTest do
  use SamplLiveWeb.ConnCase
  import Phoenix.LiveViewTest

  test &amp;quot;user can see registration form&amp;quot;, %{conn: conn} do
    {:ok, view, html} = live(conn, &amp;quot;/user_registration&amp;quot;)
    open_browser(view)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The debug process will be as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run the test. This time, we should expect the default browser to be opened and our registration form displayed.&lt;/li&gt;
&lt;li&gt;Use the element inspector in the browser to find the correct form selector.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-03/browser-inspect.png&quot; alt=&quot;registration page browser inspect&quot;/&gt;&lt;/p&gt;
&lt;p&gt;From the image above, we can see that the form element under the inspect elements section highlighted in blue has a different &lt;code&gt;query selector&lt;/code&gt; (the &lt;code&gt;id&lt;/code&gt; attribute value) specified to the one passed in &lt;code&gt;form/3&lt;/code&gt; in our test. Our test expected the &lt;code&gt;registration_form&lt;/code&gt; query selector. If we now refactor our test and pass the required query selector, it will definitely pass.&lt;/p&gt;
&lt;p&gt;We have seen that we can use &lt;code&gt;open_browser/2&lt;/code&gt; as a debugging tool for our tests. With &lt;code&gt;open_browser/2&lt;/code&gt;, we can easily verify that the correct HTML elements are rendered to users. If the correct &lt;code&gt;view_or_element&lt;/code&gt; passes, the browser opens with the displayed HTML.&lt;/p&gt;
&lt;h2&gt;Monitor Your Phoenix LiveView App in Production with AppSignal&lt;/h2&gt;
&lt;p&gt;If you also want to keep track of your live view performance in production, you can set up LiveView instrumentation in AppSignal. Once you&amp;#39;ve integrated AppSignal with Phoenix LiveView, you&amp;#39;ll be able to monitor incoming HTTP requests.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.appsignal.com/elixir/integrations/phoenix.html&quot;&gt;Check out our docs for Phoenix LiveView&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;We recommend using &lt;a href=&quot;https://blog.appsignal.com/2022/06/20/appsignal-for-phoenix-2-1-automatic-liveview-instrumentation.html&quot;&gt;our automatic LiveView instrumentation&lt;/a&gt; in the majority of cases.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;The introduction of &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html#open_browser/2&quot;&gt;&lt;code&gt;open_browser/2&lt;/code&gt;&lt;/a&gt; has made debugging LiveView tests easy and efficient. In this post, we introduced how to use &lt;code&gt;open_browser/2&lt;/code&gt; when testing to verify that the correct HTML is rendered within your live view.&lt;/p&gt;
&lt;p&gt;Happy debugging!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Generating Data Functions in Your Elixir App</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/03/21/generating-data-functions-in-your-elixir-app.html"/>
    <id>https://blog.appsignal.com/2023/03/21/generating-data-functions-in-your-elixir-app.html</id>
    <published>2023-03-21T00:00:00+00:00</published>
    <updated>2023-03-21T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In part two of this three-part series on testing data with Elixir, we&#039;ll look at using data generation functions.</summary>
    <content type="html">&lt;p&gt;In the first part of this series, we explored the ins and outs of Elixir test factories and fixtures. However, test factories bypass the rules of your Elixir application. Let&amp;#39;s turn our attention to how we can avoid this by using data generation functions.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive straight in!&lt;/p&gt;
&lt;h2&gt;Creating Data With Your Elixir App&amp;#39;s Public APIs&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll use application code to generate test data. One of the biggest
benefits of this method is that the generated data will be consistent with your application&amp;#39;s
rules. However, you need to write an extra layer of functions that your tests can easily
use.&lt;/p&gt;
&lt;h3&gt;The Test Pyramid Strategy for Your Elixir App&lt;/h3&gt;
&lt;p&gt;Before jumping into the code, it&amp;#39;s important to think about
your application&amp;#39;s public APIs and how data will be generated for each
test strategy.&lt;/p&gt;
&lt;p&gt;Saša Juric wrote about &lt;a href=&quot;https://medium.com/very-big-things/towards-maintainable-elixir-testing-b32ac0604b99&quot;&gt;how to keep a maintainable test suite in Elixir&lt;/a&gt;. In the post, he described how the most important
public API he needed to test in his app was the HTTP API layer, which is how his users interact with the app. For his app&amp;#39;s context, it was worth having a lot of test HTTP requests, even though
it might have some drawbacks on the test speed performance. In his
&lt;a href=&quot;https://martinfowler.com/bliki/TestPyramid.html&quot;&gt;test pyramid&lt;/a&gt; strategy, Saša favored interface-level tests over
lower-level ones.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-03/test-pyramid.png&quot; alt=&quot;testing_factories_with_elixir&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The image above shows different strategies you might choose for your app.&lt;/p&gt;
&lt;p&gt;You
might want a balanced pyramid with a good amount of tests in all layers
or favor unit tests above everything else.&lt;/p&gt;
&lt;p&gt;The tests in the top layer
are slower and more difficult to maintain, and they overlap with lower-layer tests.&lt;/p&gt;
&lt;p&gt;The high-level tests ensure that all modules work together, while the
lower-level tests can tell you exactly which module or function is not working properly.&lt;/p&gt;
&lt;p&gt;Your
application&amp;#39;s test pyramid strategy might have more layers with different names — for example,
the term &amp;quot;unit&amp;quot; might mean completely different things depending on who you ask.
Each strategy has its own trade-offs, and discussing them is out of the scope of this post.&lt;/p&gt;
&lt;p&gt;The most important thing to take away, though, is that you need to
understand the layers of your Elixir application and the type of data needed
to write accurate functions that generate test data.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ll give you some examples,
but ultimately, it&amp;#39;s up to you to decide what works best for your team and source code.&lt;/p&gt;
&lt;h3&gt;Extract Business Logic from Your Web Code&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s a well-known and common practice to split business logic from web code in web applications built with the Phoenix framework. In Phoenix, we usually call these
business modules &amp;quot;context&amp;quot; modules.&lt;/p&gt;
&lt;p&gt;These modules typically interact with databases,
external services, other context modules, and a lot of other functions. The functions
in context modules are usually the public API for your web layer.&lt;/p&gt;
&lt;h3&gt;An Example Using Helpers in Elixir&lt;/h3&gt;
&lt;p&gt;If you want
to invest in a lot of tests on the context level, you can create helpers for
the most-needed resources. For example, let&amp;#39;s say you have these modules:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app/accounts.ex
defmodule MyApp.Accounts do
  def signup_user(username, password) do
  # ...
  end
end

# lib/my_app/profiles.ex
defmodule MyApp.Profiles do
  def create_author_profile(user) do
  # ...
  end
end

# lib/my_app/profiles.ex
defmodule MyApp.News do
  def create_post(post_contents, author) do
  # ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we have the &lt;code&gt;Accounts&lt;/code&gt;, &lt;code&gt;Profiles&lt;/code&gt;, and &lt;code&gt;News&lt;/code&gt; contexts. Suppose
we want to test the &lt;code&gt;MyApp.News.create_post/2&lt;/code&gt; function. We first need to create an
&lt;code&gt;Author&lt;/code&gt; profile. To create an &lt;code&gt;Author&lt;/code&gt; profile, we need a &lt;code&gt;User&lt;/code&gt; account.&lt;/p&gt;
&lt;p&gt;If we have more functions in the &lt;code&gt;News&lt;/code&gt; context, or if more contexts need an &lt;code&gt;Author&lt;/code&gt;,
we always have the tedious task of creating these chained struct relationships.&lt;/p&gt;
&lt;p&gt;We can create helpers and make them available to our tests that
need valid &lt;code&gt;Author&lt;/code&gt; and &lt;code&gt;User&lt;/code&gt; structs in the system. To make these helpers only available
in the &lt;code&gt;:test&lt;/code&gt; environment, we need to tell &lt;a href=&quot;https://hexdocs.pm/mix/Mix.html&quot;&gt;Mix&lt;/a&gt;, Elixir&amp;#39;s project build tool, where to
find these files. You can update &lt;code&gt;mix.exs&lt;/code&gt; with the following configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;elixirc_paths: (
  case Mix.env() do
    :test -&amp;gt; [&amp;quot;lib&amp;quot;, &amp;quot;test/support&amp;quot;]
    _ -&amp;gt; [&amp;quot;lib&amp;quot;]
  end
 )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We tell Mix to compile the files in the &lt;code&gt;test/support&lt;/code&gt;
directory with the &lt;code&gt;lib&lt;/code&gt; directory when building the &lt;code&gt;:test&lt;/code&gt; environment. Of course,
you can use any directory name you want, but &lt;code&gt;test/support&lt;/code&gt; is a widely used convention.
This way, you can create modules only available for a &lt;code&gt;:test&lt;/code&gt; environment.
Here&amp;#39;s an example of some helpers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/support/helpers.ex
defmodule MyApp.Helpers do
  def create_user(opts \\ []) do
    username = Keyword.get(opts, :username, &amp;quot;test_user&amp;quot;)
    password = Keyword.get(opts, :password, &amp;quot;p4ssw0rd&amp;quot;)

    {:ok, user} = MyApp.Accounts.signup_user(username, password)
  end

  def create_author(opts \\ []) do
    user = Keyword.get_lazy(opts, :user, &amp;amp;signup_user/0)

    {:ok, author} = MyApp.Profiles.create_author_profile(user)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;MyApp.Helpers&lt;/code&gt; module above, we create wrappers over our application&amp;#39;s
core API with convenient defaults to use in tests. In real life, we wouldn&amp;#39;t create
users with the password &lt;code&gt;&amp;quot;p4ss0wrd&amp;quot;&lt;/code&gt; by default, but for our test scripts, it&amp;#39;s
fine.&lt;/p&gt;
&lt;p&gt;We also use &lt;code&gt;Keyword.get/3&lt;/code&gt; to overwrite
important attributes of the created resources. This avoids unnecessary
side effects, especially when the caller provides us with a &lt;code&gt;user&lt;/code&gt; to the &lt;code&gt;create_author/1&lt;/code&gt;
helper. That&amp;#39;s why we use &lt;code&gt;Keyword.get_lazy/3&lt;/code&gt; in the &lt;code&gt;create_author/1&lt;/code&gt; helper.
&lt;code&gt;get_lazy&lt;/code&gt; will only invoke the &lt;code&gt;signup_user&lt;/code&gt; function if the &lt;code&gt;:user&lt;/code&gt; key doesn&amp;#39;t
exist.&lt;/p&gt;
&lt;h3&gt;Invoking and Customizing Helpers in Elixir&lt;/h3&gt;
&lt;p&gt;We can also be strict with data patterns here since we don&amp;#39;t expect the creation of
users or authors to fail. The caller can invoke and customize these helpers for the needs of the test. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;user = create_user(username: &amp;quot;test_user_2&amp;quot;)

create_author(user: user)
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;When writing your tests, you can use the examples above and write something similar:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/news/news_test.exs

# module definition and stuff

alias MyApp.Helpers

# maybe other tests in the middle

test &amp;quot;creates new post with given the contents&amp;quot; do
  author = Helpers.create_author()

  assert {:ok, post} = News.create_post(&amp;quot;My first post!&amp;quot;, author)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, we use &lt;code&gt;alias MyApp.Helpers&lt;/code&gt; to make our helper module
functions accessible with a few characters. It makes the use of these functions as
convenient as the test factories provided by ExMachina.&lt;/p&gt;
&lt;p&gt;A cool advantage of this approach is that if your editor uses a language server like &lt;a href=&quot;https://github.com/elixir-lsp/elixir-ls&quot;&gt;&lt;code&gt;ElixirLS&lt;/code&gt;&lt;/a&gt;, you
can quickly discover or navigate these functions easily. The &lt;code&gt;build(:user)&lt;/code&gt;
pattern doesn&amp;#39;t allow the editors of today to track the definition code directly.&lt;/p&gt;
&lt;h3&gt;Breaking the Helpers Module Down Into Other Modules&lt;/h3&gt;
&lt;p&gt;As the &lt;code&gt;Helpers&lt;/code&gt; module grows and gets more complex,
you might want to break it down into different modules.&lt;/p&gt;
&lt;p&gt;For example, you could break it down
by context - &lt;code&gt;AccountsHelper&lt;/code&gt;, &lt;code&gt;ProfilesHelpers&lt;/code&gt;, etc. The best naming and file
organization depends on each application&amp;#39;s needs, so I&amp;#39;ll leave it up to you.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Helpers&lt;/code&gt; example discussed here might have left you thinking: &amp;quot;This
looks like factories.&amp;quot; And you&amp;#39;re not wrong!&lt;/p&gt;
&lt;p&gt;This is a different implementation of test
factories. Instead of creating examples of data uncoupled with your application&amp;#39;s rules, here
we tie your application&amp;#39;s rules and your test examples together.&lt;/p&gt;
&lt;p&gt;It works like
the factory pattern because your tests aren&amp;#39;t coupled with the way the underlying struct
is built.&lt;/p&gt;
&lt;p&gt;This example satisfies the demands of the context modules layer, but what about the
other layers? In the next section, we&amp;#39;ll explore when using public APIs isn&amp;#39;t enough
and how to generate data examples for these cases.&lt;/p&gt;
&lt;h2&gt;Beyond Public APIs: Data Examples&lt;/h2&gt;
&lt;p&gt;One of the main advantages of using your Elixir app&amp;#39;s public API to generate data for your
tests is that the data will comply with your app&amp;#39;s rules and database constraints.&lt;/p&gt;
&lt;p&gt;While the speed and coupling with the database may not always be ideal, this is
a small price to pay to ensure your data&amp;#39;s validity.&lt;/p&gt;
&lt;p&gt;As your app grows in
complexity, you may need to add a layer of tests that run in memory
to improve performance. It is also not uncommon for systems to talk to
other systems through network APIs. In these cases, your application likely won&amp;#39;t
have enough control over the rules to build valid data. You may
need to rely on API specifications provided by the remote system and snapshot
some examples to use in your tests.&lt;/p&gt;
&lt;p&gt;Data examples built in memory and
decoupled from database or application rules can be extremely helpful.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s
explore a lightweight — and somewhat controversial — method of generating data examples
within your application modules.&lt;/p&gt;
&lt;h3&gt;Writing Data Examples in Data Definition Modules&lt;/h3&gt;
&lt;p&gt;Years ago, a colleague invited me to watch an episode of &lt;a href=&quot;https://www.rubytapas.com/2015/09/17/episode-342-example-data/&quot;&gt;Ruby Tapas presented by Avid Grimm&lt;/a&gt;.
Inspired by the book &lt;a href=&quot;https://www.poodr.com/&quot;&gt;Practical Object-Oriented Design by Sandi Metz&lt;/a&gt;, Grimm talks about
writing data examples in the modules where the data definition lives. This can serve as executable documentation and also be
used in tests.&lt;/p&gt;
&lt;p&gt;Some people might not be big fans of mixing test data with application code. But,
as long as it is clear that the data is meant as an example and not for production use, it can be
a useful technique.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s say you&amp;#39;re writing a &lt;code&gt;GitHub&lt;/code&gt; client, and
you&amp;#39;re defining the &lt;code&gt;Repo&lt;/code&gt; struct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# github/repo.ex
defmodule GitHub.Repo do
  defstruct [
    :id,
    :name,
    :full_name,
    :description,
    :owner_id,
    :owner_url,
    :private,
    :html_url,
    :url
  ]

  @typespec t :: %__MODULE__{
    id: pos_integer(),
    name: String.t(),
    full_name: String.t(),
    description: String.t(),
    owner_id: pos_integer(),
    owner_url: String.t(),
    private: boolean(),
    html_url: String.t(),
    url: String.t()
  }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we define the &lt;code&gt;GitHub.Repo&lt;/code&gt; struct and document the
keys type with &lt;code&gt;typespec&lt;/code&gt;. While this provides a lot of information, extra documentation
can help readers understand the data&amp;#39;s nuances.&lt;/p&gt;
&lt;p&gt;In this example, can you
tell the difference between the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;full_name&lt;/code&gt;? Or &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;html_url&lt;/code&gt;? It&amp;#39;s hard
to tell, right?&lt;/p&gt;
&lt;p&gt;We can make it clearer. Let&amp;#39;s add an example of the values:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# github/repo.ex
def example do
  %GitHub.Repo{
    id: 1296269,
    name: &amp;quot;Hello-World&amp;quot;,
    full_name: &amp;quot;octocat/Hello-World&amp;quot;,
    description: &amp;quot;This your first repo!&amp;quot;,
    owner_id: 1,
    owner_url: &amp;quot;https://api.github.com/users/octocat&amp;quot;,
    private: false,
    html_url: &amp;quot;https://github.com/octocat/Hello-World&amp;quot;,
    url: &amp;quot;https://api.github.com/repos/octocat/Hello-World&amp;quot;
  }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Defining the &lt;code&gt;example/0&lt;/code&gt; function, which returns an example of the data
structure, can be useful in various ways.&lt;/p&gt;
&lt;p&gt;For example, if you&amp;#39;re
exploring the code in IEx (the Elixir interactive shell), you could invoke the function
to quickly experiment with a complex function call. Livebook material (interactive
documents that allow users to run code) could use these functions to show an example
of the data shape. In production, the example values could be used as hints for
form fields.&lt;/p&gt;
&lt;h3&gt;Customize Key Values of the &lt;code&gt;example&lt;/code&gt; Function&lt;/h3&gt;
&lt;p&gt;One of the main purposes of an example function, however, is to create data for tests.
You can make the &lt;code&gt;example&lt;/code&gt; function even more useful by allowing the caller to
customize the key values. Here&amp;#39;s an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def example(attributes \\ []) do
  struct!(
    %GitHub.Repo{
      id: 1296269,
      name: &amp;quot;Hello-World&amp;quot;,
      full_name: &amp;quot;octocat/Hello-World&amp;quot;,
      description: &amp;quot;This your first repo!&amp;quot;,
      owner_id: 1,
      owner_url: &amp;quot;https://api.github.com/users/octocat&amp;quot;,
      private: false,
      html_url: &amp;quot;https://github.com/octocat/Hello-World&amp;quot;,
      url: &amp;quot;https://api.github.com/repos/octocat/Hello-World&amp;quot;
    },
    attributes
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use Elixir&amp;#39;s &lt;code&gt;struct!/2&lt;/code&gt; kernel function to build structs dynamically.
The great thing about &lt;code&gt;struct!&lt;/code&gt; is that it fails if any unexpected keys are set. Now
we can invoke the &lt;code&gt;example/1&lt;/code&gt; function and customize the data in any way we want:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;renders anchor tag to the repository&amp;quot; do
  repo = GitHub.Repo.example(html_url: &amp;quot;http://test.com&amp;quot;)

  assert hyperlink_tag(repo) =~ &amp;quot;&amp;lt;a href=\&amp;quot;http://test.com\&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, we can easily create a &lt;code&gt;GitHub.Repo&lt;/code&gt; and customize its &lt;code&gt;html_url&lt;/code&gt;
key for our test.&lt;/p&gt;
&lt;h3&gt;Similarities to Test Factories for Elixir&lt;/h3&gt;
&lt;p&gt;&amp;quot;Wait, isn&amp;#39;t this just factories again?&amp;quot; you might be wondering.
And you&amp;#39;re right! It&amp;#39;s similar to the factory mechanism found in other libraries.
While this can make the functions easy to navigate and localize using your editor,
if you rename the &lt;code&gt;GitHub.Repo&lt;/code&gt; module, you&amp;#39;ll need to find and replace a bunch of
tests. However, modern editors are usually powerful enough to handle the task in
a single command, so this shouldn&amp;#39;t be a big issue.&lt;/p&gt;
&lt;p&gt;Another interesting aspect of providing data examples in your struct modules
is that you don&amp;#39;t need to organize your factory files, as they are organized together within your application code.&lt;/p&gt;
&lt;p&gt;The popular ExMachina factories, your own helper functions that use your application&amp;#39;s rules,
and data example functions in your structs are all examples of factory pattern
implementations.&lt;/p&gt;
&lt;h3&gt;Using ExMachina&lt;/h3&gt;
&lt;p&gt;Using ExMachina to create your factories helps you separate
test data from production code and gives you convenient functions. For example,
when you define a factory using ExMachina, you can use that definition to generate test data
with different strategies, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build&lt;/code&gt; to generate in-memory structs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insert&lt;/code&gt; to load data in a database&lt;/li&gt;
&lt;li&gt;&lt;code&gt;build_list&lt;/code&gt; to generate multiple items in a list&lt;/li&gt;
&lt;li&gt;&lt;code&gt;string_params_for&lt;/code&gt; to create map params with keys as strings like you would
receive in a Phoenix controller&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are a few examples of functions that ExMachina can offer — and it has more! The
convenience of these functions is debatable, though. For example,
having the &lt;code&gt;insert&lt;/code&gt; function so conveniently available could make you unnecessarily insert things into a database. And how often do
your controller parameters&amp;#39; keys and value formats match the schema attributes generated by
the &lt;code&gt;string_params_for&lt;/code&gt; to make it really worth it? However, these convenient
functions do the job for simple cases and offer a foundation for your entire test suite.&lt;/p&gt;
&lt;h2&gt;Up Next: Elixir Libraries for Test Data&lt;/h2&gt;
&lt;p&gt;Now that you understand the fundamental techniques for generating test data in
Elixir, you should be able to do this for your own project without much trouble.&lt;/p&gt;
&lt;p&gt;In the third and final part of this series, we&amp;#39;ll dive into some Elixir libraries for your test data, including ExMachina, ExZample, Faker, and StreamData.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Test Factories and Fixtures for Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/02/28/an-introduction-to-test-factories-and-fixtures-for-elixir.html"/>
    <id>https://blog.appsignal.com/2023/02/28/an-introduction-to-test-factories-and-fixtures-for-elixir.html</id>
    <published>2023-02-28T00:00:00+00:00</published>
    <updated>2023-02-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first part of this three-part series, we&#039;ll give an overview of Elixir test factories and fixtures.</summary>
    <content type="html">&lt;p&gt;Writing tests is an essential part of any Elixir
developer&amp;#39;s routine. We&amp;#39;re constantly chasing knowledge on how to
write better tests,
improving their speed and readability.&lt;/p&gt;
&lt;p&gt;In this three-part series, we&amp;#39;ll explore
test data generation in Elixir. Whether you are a mid-level or senior-level Elixir developer, this series
will provide valuable insights to help improve the testing process for your projects.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start by digging into where test factories come from and why they are so
popular in Elixir.&lt;/p&gt;
&lt;h2&gt;What are Test Factories in Elixir?&lt;/h2&gt;
&lt;p&gt;Test factories are functions for generating data, commonly used in the &lt;code&gt;:test&lt;/code&gt;
environment.&lt;/p&gt;
&lt;p&gt;Test factory libraries like &lt;a href=&quot;https://hex.pm/packages/ex_machina&quot;&gt;ExMachina&lt;/a&gt; are widely used among Elixir developers. If you look at the &lt;a href=&quot;https://hex.pm&quot;&gt;hex.pm&lt;/a&gt; stats, you&amp;#39;ll see that ExMachina downloads aren&amp;#39;t far behind the most popular Elixir database library: &lt;a href=&quot;https://hex.pm/packages/ecto&quot;&gt;Ecto&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They allow you to create complex data structures using a very convenient
interface that requires few inputs. Here&amp;#39;s an example using ExMachina:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; user = ExMachina.insert(:user)
%User{
  id: &amp;quot;usr_xlkt&amp;quot;
  name: &amp;quot;Abilidebob&amp;quot;
  accounts: %Account{
    id: &amp;quot;acc_xktt&amp;quot;
    #....
  }
  #...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a few characters, I can grab an example of a &lt;code&gt;:user&lt;/code&gt; in the system. Test
factories are inspired by the &lt;a href=&quot;https://en.wikipedia.org/wiki/Factory_method_pattern&quot;&gt;factory method pattern&lt;/a&gt;, a design pattern that allows a caller to create objects without knowing the specific
module or class of the data that will be created.&lt;/p&gt;
&lt;p&gt;Okay, this might sound a little bit
complicated! Let&amp;#39;s look at the following ExMachina code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;user = ExMachina.insert(:user)

do_something(user)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, ExMachina is using the &lt;code&gt;:user&lt;/code&gt; atom to dispatch to
a function that can create examples of &lt;code&gt;%User{}&lt;/code&gt; structs. If you write your tests in a &lt;a href=&quot;https://ulisses.dev/elixir/2020/02/19/elixir-style-for-maintanability.html#use-compile-friendly-style-in-lib-dynamic-style-in-test&quot;&gt;dynamic style&lt;/a&gt;, you can rename the &lt;code&gt;User&lt;/code&gt; struct without refactoring any tests, except the factory function.&lt;/p&gt;
&lt;p&gt;The factory pattern isn&amp;#39;t only helpful in tests. You can also use it to create or dispatch
functions from dynamic sources, such as user inputs.&lt;/p&gt;
&lt;p&gt;For example, you could use a factory
function to create an account based on a user&amp;#39;s input. A factory function is useful here because your
application&amp;#39;s users don&amp;#39;t know the name of your source code&amp;#39;s modules or functions — and you should keep
it that way. You need to create a mechanism that links a user&amp;#39;s input with the
correct constructor:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def new_account(&amp;quot;hobbyist&amp;quot;), do: HobbyAccount.new()
def new_account(&amp;quot;professional&amp;quot;), do: ProfessionalAccount.new()
def new_account(&amp;quot;enterprise&amp;quot;), do: EnterpriseAccount.new()
def new_account(account_type), do: raise ImpossibleAccount, account_type
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the previous example, I built a factory function named &lt;code&gt;new_account/1&lt;/code&gt; that takes a string
as an argument and uses pattern matching to determine which function to call. For example, if
a user selects the &amp;quot;Hobbyist&amp;quot; option from a selection box, the application will receive a
&lt;code&gt;&amp;quot;hobbyist&amp;quot;&lt;/code&gt; string as the input. The &lt;code&gt;new_account/1&lt;/code&gt; function can use the string to
dispatch the &lt;code&gt;HobbyAccount.new/1&lt;/code&gt; function and generate a &lt;code&gt;HobbyAcccount&lt;/code&gt; struct.&lt;/p&gt;
&lt;h2&gt;Why Use Test Factories for Elixir?&lt;/h2&gt;
&lt;p&gt;Test factories are good options for long-term test suite maintainability because of the
following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learnability&lt;/strong&gt; - factories document what data structures can look like in production&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reusability&lt;/strong&gt; - data examples generated by factories can be reused in many different tests&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Productivity&lt;/strong&gt; - developers can invoke complex data examples from factories by typing a few characters instead
of building new examples from scratch every time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Changeability&lt;/strong&gt; - tests that rely on central factories always have the most up-to-date examples&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These properties aren&amp;#39;t inherently part of the factories alone. A software development team&amp;#39;s discipline is required.&lt;/p&gt;
&lt;p&gt;For example, if you don&amp;#39;t provide
relevant real-world examples in your factories, they will not be a source of
knowledge for developers. If your factories produce values that other developers
tend to override, they will more likely stop using those factories because they
are not convenient anymore.&lt;/p&gt;
&lt;p&gt;But when a factory pattern is well-maintained, it
helps developers to maintain a sustainable test suite that lasts for a long time.&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;ll turn our attention to test fixtures.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Test Fixtures in Elixir&lt;/h2&gt;
&lt;p&gt;In testing, a &lt;a href=&quot;https://en.wikipedia.org/wiki/Test_fixture&quot;&gt;fixture&lt;/a&gt; is data that we prepare before running a test. Factories
are functions that generate test data on demand.&lt;/p&gt;
&lt;p&gt;Factories can complement fixtures — you don&amp;#39;t necessarily
have to opt for one over the other. For example, you can prepare a test fixture that uses a factory
function to insert data in a database.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s why we can sometimes use these terms interchangeably and
still be understood. Often, people associate the term &amp;quot;fixtures&amp;quot; with the feature
in Ruby on Rails. &lt;a href=&quot;https://api.rubyonrails.org/v3.1/classes/ActiveRecord/Fixtures.html&quot;&gt;Ruby On Rails fixtures&lt;/a&gt; have
the following properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data is defined in YAML files, not inline in the tests.&lt;/li&gt;
&lt;li&gt;All defined data is loaded in the database before each test run.&lt;/li&gt;
&lt;li&gt;You can reference these fixtures through dynamic methods generated by the framework.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, different frameworks or libraries implement test fixtures differently. After all, the main purpose of test fixtures is to provide
a common starting point for your tests.&lt;/p&gt;
&lt;p&gt;There are basically two main kinds of test fixtures: inline
and implicit.&lt;/p&gt;
&lt;h3&gt;Inline Test Fixtures&lt;/h3&gt;
&lt;p&gt;The simplest inline fixture you can do in Elixir is the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;creates an author profile&amp;quot; do
  user = MyApp.Repo.insert!(%User{id: &amp;quot;usr_123&amp;quot;, name: &amp;quot;Abilidebob&amp;quot;})

  # rest of the test code
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With a basic &lt;code&gt;Repo.insert!/1&lt;/code&gt;, we make a database fixture for a test. That test
can rely on the user with the id &lt;code&gt;&amp;quot;usr_123&amp;quot;&lt;/code&gt; always being present in the database.&lt;/p&gt;
&lt;p&gt;This example code assumes the test suite uses &lt;a href=&quot;https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Sandbox.html&quot;&gt;Ecto sandbox setup&lt;/a&gt;, which
always reverts database changes made during a test after its execution.&lt;/p&gt;
&lt;p&gt;So we don&amp;#39;t need
to worry at the beginning of the test if the user with the same id is already inserted in a previous
execution. We can even use a factory function to insert the data, and it still would be
correct to call it a test fixture. This fixture is explicit and inline with the tests.&lt;/p&gt;
&lt;h3&gt;Implicit Test Fixtures&lt;/h3&gt;
&lt;p&gt;Like in Ruby on Rails, it&amp;#39;s possible to create implicit fixtures that
multiple tests can share using the &lt;a href=&quot;https://hexdocs.pm/ex_unit/1.14.2/ExUnit.CaseTemplate.html&quot;&gt;&lt;code&gt;ExUnit.CaseTemplate&lt;/code&gt;&lt;/a&gt;
test template:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/support/data_case.ex
defmodule MyApp.DataCase do
  use ExUnit.CaseTemplate

  # ... bunch of other code here

  setup _context do
    user = %User{id: &amp;quot;usr_123&amp;quot;, name: &amp;quot;Abilidebob&amp;quot;}
    %{user: MyApp.Repo.insert!(user)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above uses the &lt;code&gt;setup&lt;/code&gt; directive to make all tests that use this template
insert a user. Then we return a map, where the key is &lt;code&gt;:user&lt;/code&gt;, and the value
is our recently created user. Any test can quickly reference this by using the key &lt;code&gt;:user&lt;/code&gt; and grabbing it
from the test context. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.MyTest do
  use MyApp.DataCase

  test &amp;quot;hello world&amp;quot;, %{user: user} do
    # then I use my `user` here
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ExUnit Contexts&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/ex_unit/ExUnit.html&quot;&gt;&lt;code&gt;ExUnit&lt;/code&gt;&lt;/a&gt; test contexts are a flexible mechanism where you can build things to share between multiple tests.&lt;/p&gt;
&lt;p&gt;The biggest disadvantage of fixtures is their
impact on test suite speed and test isolation if you share them too much. The speed can decrease because
all the code you put in setup blocks of test templates always runs before each test,
even when you don&amp;#39;t need the data from the test context.&lt;/p&gt;
&lt;p&gt;So be careful how
much data you add and how multiple modules use the templates. Otherwise, as the speed
decreases, implicit coupling between multiple tests on the same test fixtures
can also increase. A small change to a test fixture shared in this way can make multiple tests fail for no
obvious reason.&lt;/p&gt;
&lt;h3&gt;Sharing Bypass Instances Between Multiple Tests&lt;/h3&gt;
&lt;p&gt;Developers favor factory libraries over Ruby On Rails fixtures because they&amp;#39;d rather have testing
data explicitly invoked from tests than implicit data generated far from where it is
needed. In other words, they prefer inline test fixtures.&lt;/p&gt;
&lt;p&gt;Explicitness contributes to better long-term maintenance. Implicit test fixtures are
better for things that are very cheap to build and have a very general purpose, and low
coupling with testing specifics.&lt;/p&gt;
&lt;p&gt;A good example is the &lt;a href=&quot;https://hexdocs.pm/bypass/Bypass.html&quot;&gt;&lt;code&gt;Bypass&lt;/code&gt;&lt;/a&gt; instance:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# test/support/data_case.ex
defmodule MyApp.GithubIntegrationCase do
  use ExUnit.CaseTemplate

  # ... bunch of other code here

  setup _context do
    bypass = Bypass.open()
    client = GitHub.new(endpoint: &amp;quot;http://localhost:#{bypass.port}/&amp;quot;)
    %{bypass: bypass, client: client}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, I prepare a test template for my &lt;code&gt;GitHub&lt;/code&gt; client integration tests.
The setup code creates a fake HTTP server using Bypass. The &lt;code&gt;GitHub&lt;/code&gt; client uses this server to make HTTP requests during the tests using the &lt;code&gt;client&lt;/code&gt; settings.&lt;/p&gt;
&lt;p&gt;Now, all tests that use &lt;code&gt;MyApp.GithubIntegrationCase&lt;/code&gt; can use the &lt;code&gt;:bypass&lt;/code&gt; and
&lt;code&gt;:client&lt;/code&gt; keys to pull the fake server and its settings, respectively, from the test context.&lt;/p&gt;
&lt;p&gt;Here is how these fixtures might be used in a test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.MyTest do
  use MyApp.GithubIntegrationCase

  test &amp;quot;user registration&amp;quot;, %{bypass: bypass, client: client} do
    Bypass.expect(bypass, :post, &amp;quot;/users&amp;quot;) do
      # ... setup expectations and return a success response
    end

    # Use the `client` tag to make HTTP requests with the `GitHub` client
    {:ok, user} = GitHub.create_user(client, name: &amp;quot;Abilidebob&amp;quot;)

    # Assert that the user is correct
    # ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&amp;#39;ve worked with other frameworks, such as Ruby on Rails, you might
be surprised that Elixir doesn&amp;#39;t have a popular fixture library.&lt;/p&gt;
&lt;p&gt;I believe that&amp;#39;s because the ExUnit test context can share test fixtures pretty easily. The fixture pattern is usually discouraged due to its impact on test
suite speed and maintainability.&lt;/p&gt;
&lt;h2&gt;Test Factories and Your Elixir App&amp;#39;s Rules&lt;/h2&gt;
&lt;p&gt;In his excellent post &lt;a href=&quot;https://medium.com/very-big-things/towards-maintainable-elixir-testing-b32ac0604b99&quot;&gt;Towards Maintainable Elixir: Testing&lt;/a&gt;, Saša Jurić
provides valuable tips on how to maintain a test suite. The focus of the post is
on increasing your confidence in tests and reducing test overlap.
There is no mention of test factories. Instead, Saša uses his own application
interface to prepare test data. The reason he avoids test factories is because of their
biggest problem: they bypass your application&amp;#39;s rules.&lt;/p&gt;
&lt;p&gt;When you set up a test factory for your test suite, the data examples it generates are completely
detached from your application code&amp;#39;s rules.&lt;/p&gt;
&lt;p&gt;For example, let&amp;#39;s say you have a &lt;code&gt;User&lt;/code&gt;
entity with an &lt;code&gt;is_author&lt;/code&gt; flag, but that flag is only set to true if the user has
one author profile. Here&amp;#39;s an example of how the production code would look:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def create_author_profile(user) do
  author_profile = build_author_profile(user)
  user = Ecto.Changeset.change(user, %{is_author: true})

  Multi.new()
  |&amp;gt; Multi.update(:user, user)
  |&amp;gt; Multi.insert(:author_profile, author_profile)
  |&amp;gt; Repo.transaction()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s say that you now want to create the &lt;code&gt;:user&lt;/code&gt; and &lt;code&gt;:author&lt;/code&gt; factories for your test factory.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example using the ExMachina library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def user_factory do
  %User{name: &amp;quot;Abili&amp;quot;}
end

def author_factory do
  %Author{
    name: &amp;quot;Mr. DeBob&amp;quot;,
    user: build(:user, is_author: true)
  }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the factories are straightforward. They build structs and assign
values that make sense. However, have you noticed the &lt;code&gt;is_author: true&lt;/code&gt; part? That tiny part
is actually the biggest problem with factories: we have to duplicate our business rules!&lt;/p&gt;
&lt;p&gt;Imagine having to remember to replicate every single aspect of multiple data modifications
in your factories. Not only does this add extra code that needs to be maintained, but it can
also mislead developers into trusting invalid data that your app cannot produce.&lt;/p&gt;
&lt;p&gt;The invalid data generated by factories can lead you to write unnecessarily defensive code.
For example, if someone forgets to include &lt;code&gt;is_author: true&lt;/code&gt; in the factory, you might
write code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;if user.is_author || Profiles.find_author(user_id) do
# logic for users that are author here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the previous example, a check is written for the &lt;code&gt;is_author&lt;/code&gt; flag. It is
assumed the flag isn&amp;#39;t always reliable — after all, the factory generates authors with
&lt;code&gt;is_author: false&lt;/code&gt; users. As a result, we decide to make a query in the database to double-check
if the user is an author.&lt;/p&gt;
&lt;p&gt;As you can see, factories that are decoupled from application rules aren&amp;#39;t always perfect
and can cause problems if they are not properly maintained.&lt;/p&gt;
&lt;p&gt;Despite their issues,
factories are a popular pattern for generating test data in Elixir. They offer convenient functions to build complex data structures, and you can
invoke them on demand.&lt;/p&gt;
&lt;p&gt;However, using factories adds an extra layer of maintainability, an extra
worry to put in your team&amp;#39;s minds. The worry is usually negligible when your application
code is small, but can become problematic as your business and code grow more complex.&lt;/p&gt;
&lt;h2&gt;Up Next: Generating Data Functions in Your Elixir App&lt;/h2&gt;
&lt;p&gt;In this first part of our three-part series, we introduced test factories and test fixtures for Elixir. We then explored the biggest issue with test factories: the fact that they bypass your application&amp;#39;s rules.&lt;/p&gt;
&lt;p&gt;In part two, we&amp;#39;ll explore how you can combat this by creating data generation functions using your
application&amp;#39;s rules.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Under the Hood of Ecto</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/02/14/under-the-hood-of-ecto.html"/>
    <id>https://blog.appsignal.com/2023/02/14/under-the-hood-of-ecto.html</id>
    <published>2023-02-14T00:00:00+00:00</published>
    <updated>2023-02-14T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how Ecto&#039;s internals work by looking at its four major modules in detail.</summary>
    <content type="html">&lt;p&gt;Ecto is a toolkit for mapping database objects to Elixir structs and provides a unified interface to manipulate that data.&lt;/p&gt;
&lt;p&gt;In this post, we will dive into the internals of Ecto — its major components, their functions, and how they work. In doing so, we&amp;#39;ll demystify some of the apparent magic behind Ecto.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Ecto&amp;#39;s Modules&lt;/h2&gt;
&lt;p&gt;Ecto is made up of four major modules — &lt;code&gt;Repo&lt;/code&gt;, &lt;code&gt;Query&lt;/code&gt;, &lt;code&gt;Schema&lt;/code&gt;, and &lt;code&gt;Changeset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll look at each in turn. Let’s start with the &lt;code&gt;Repo&lt;/code&gt; module.&lt;/p&gt;
&lt;h2&gt;Repo Module&lt;/h2&gt;
&lt;p&gt;If you use Ecto with a database (like most users out there), Repo is the heart of Ecto. It binds everything together and provides a centralized point of communication between a database and your application. Repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;maintains connections&lt;/li&gt;
&lt;li&gt;executes queries against a database&lt;/li&gt;
&lt;li&gt;provides an API to write migrations that interact with the database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s get started with Repo. Simply call &lt;code&gt;use Ecto.Repo&lt;/code&gt; inside your Repo module. If you use &lt;code&gt;mix phx.new&lt;/code&gt; to generate your Elixir project, this is done automatically for you.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/my_app/repo.ex
defmodule MyApp.Repo
  use Ecto.Repo,
      otp_app: :my_app,
      adapter: Ecto.Adapters.Postgres
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These few lines of code define the repo. Putting it under the Supervision tree inside &lt;code&gt;application.ex&lt;/code&gt; gives you access to a whole set of functions provided by Repo to interact with a database. Again, this is code that is generated for you when using Phoenix:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Application do
  use Application

  @impl true
  def start(_type, _args) do
    children = [
      # Start the Ecto repository
      MyApp.Repo,
      # Other Children...
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the few lines of code above, you get the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Access to the &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#summary&quot;&gt;full &lt;code&gt;Ecto.Repo API&lt;/code&gt;&lt;/a&gt; included in &lt;code&gt;MyApp.Repo&lt;/code&gt;.
The most common use cases include fetching records with &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#c:all/2&quot;&gt;&lt;code&gt;MyApp.Repo.all/2&lt;/code&gt;&lt;/a&gt;, inserting new records with &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#c:insert/2&quot;&gt;&lt;code&gt;MyApp.Repo.insert/2&lt;/code&gt;&lt;/a&gt;, and updating records with &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#c:update/2&quot;&gt;&lt;code&gt;MyApp.Repo.update/2&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://github.com/elixir-ecto/ecto/blob/bbe380e49cb52b1ad4114372cfd73126cf34f996/lib/ecto/repo/supervisor.ex#L1&quot;&gt;Supervisor&lt;/a&gt; starts that keeps track of all the processes required to keep Ecto working.
The Supervision tree initializes the adapter (&lt;code&gt;Ecto.Adapters.Postgres&lt;/code&gt;, in this case), which is responsible for all communication with the database.
The Postgres adapter, in turn, starts a connection pool to your database using the &lt;a href=&quot;https://github.com/elixir-ecto/db_connection&quot;&gt;&lt;code&gt;DBConnection&lt;/code&gt; library&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A query planner starts that&amp;#39;s responsible for planning and normalizing a query and its parameters.
It also keeps a cache of all planned queries in an ETS table.
We will learn more about this when we get to the &lt;code&gt;Query&lt;/code&gt; module.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Monitor Queries Sent to Ecto from Your Elixir Application&lt;/h3&gt;
&lt;p&gt;In addition, Ecto also automatically publishes telemetry events that can be monitored.
For example, to monitor statistics for all the queries sent to Ecto, you can subscribe to the &lt;code&gt;[:my_app, :repo, :query]&lt;/code&gt; event with telemetry.&lt;/p&gt;
&lt;p&gt;Then, each time a query is performed, this event triggers some query metadata that includes the time spent executing the query, retrieving the data from the database, and more.&lt;/p&gt;
&lt;p&gt;For more details, see this &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#module-telemetry-events&quot;&gt;full list of Ecto telemetry events&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are many options available to configure the Repo or the adapter as per your needs, but that&amp;#39;s out of the scope of this post. Let&amp;#39;s just take a very quick look at how you can monitor queries with AppSignal.&lt;/p&gt;
&lt;h3&gt;Instrumenting Ecto Queries with AppSignal in Your Elixir App&lt;/h3&gt;
&lt;p&gt;AppSignal automatically instruments Ecto so you can get insights into Queries running in your Phoenix or Plug applications. Make sure the &lt;code&gt;:otp_app&lt;/code&gt; configuration option matches your app’s OTP app name, and you’re all set!&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of how an Ecto query will look in AppSignal:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-02/ecto-query.png&quot; alt=&quot;Ecto query&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.appsignal.com/elixir/integrations/ecto.html&quot;&gt;Read more in our Ecto docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;Check out our AppSignal for Elixir page&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Query Module&lt;/h2&gt;
&lt;p&gt;The Query module provides a unified API to write database-agnostic queries in Elixir.
Note that building database queries with functions provided by the &lt;code&gt;Ecto.Query&lt;/code&gt; module does not result in the queries being executed.&lt;/p&gt;
&lt;p&gt;These functions return a query in the form of an &lt;code&gt;Ecto.Query&lt;/code&gt; struct.
Nothing is actually sent to the database until the built &lt;code&gt;%Ecto.Query{}&lt;/code&gt; is passed to one of the functions provided by the Repo module.&lt;/p&gt;
&lt;p&gt;As an example, let’s see a simple query that selects all users above 18 years of age:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;age = 18
query = from u in &amp;quot;users&amp;quot;,
                where: u.age &amp;gt; ^age,
                select: u.name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type this into an IEx console and you will see that it creates a struct like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#Ecto.Query&amp;lt;from u0 in &amp;quot;users&amp;quot;, where: u0.age &amp;gt; 18, select: u0.name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also print it as a full map to see everything inside it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(9)&amp;gt; IO.inspect(query, structs: false)
%{
  __struct__: Ecto.Query,
  aliases: %{},
  assocs: [],
  combinations: [],
  distinct: nil,
  from: %{
    __struct__: Ecto.Query.FromExpr,
    as: nil,
    file: &amp;quot;iex&amp;quot;,
    hints: [],
    line: 40,
    params: [],
    prefix: nil,
    source: {&amp;quot;users&amp;quot;, nil}
  },
  group_bys: [],
  havings: [],
  joins: [],
  limit: nil,
  lock: nil,
  offset: nil,
  order_bys: [],
  prefix: nil,
  preloads: [],
  select: %{
    __struct__: Ecto.Query.SelectExpr,
    aliases: %{},
    expr: {{:., [], [{:&amp;amp;, [], [0]}, :name]}, [], []},
    fields: nil,
    file: &amp;quot;iex&amp;quot;,
    line: 40,
    params: [],
    subqueries: [],
    take: %{}
  },
  sources: nil,
  updates: [],
  wheres: [
    %{
      __struct__: Ecto.Query.BooleanExpr,
      expr: {:&amp;gt;, [], [{{:., [], [{:&amp;amp;, [], [0]}, :age]}, [], []}, {:^, [], [0]}]},
      file: &amp;quot;iex&amp;quot;,
      line: 40,
      op: :and,
      params: [{18, {0, :age}}],
      subqueries: []
    }
  ],
  windows: [],
  with_ctes: nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is much more interesting — it shows exactly how the simple query is represented internally in Ecto.
&lt;code&gt;Ecto.Query.FromExpr&lt;/code&gt; contains details about the table we are querying (&lt;code&gt;users&lt;/code&gt;).&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;ASTs in the Query&lt;/h3&gt;
&lt;p&gt;The other two expressions we see in the query are much more complex, but this is something that the adapters understand and convert to the query.
If you look closely, they are &lt;code&gt;AST&lt;/code&gt;s.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are interested in learning more about ASTs, check out &lt;a href=&quot;https://blog.appsignal.com/2021/09/07/an-introduction-to-metaprogramming-in-elixir.html&quot;&gt;An Introduction to Metaprogramming in Elixir&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see what the code looks like for this expression:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Macro.to_string({:&amp;gt;, [], [{{:., [], [{:&amp;amp;, [], [0]}, :age]}, [], []}, {:^, [], [0]}]})
&amp;quot;&amp;amp;0.age() &amp;gt; ^0&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is our condition in &lt;code&gt;where&lt;/code&gt;, just normalized into terms the adapters understand.&lt;/p&gt;
&lt;p&gt;The adapter does the final translation of the query to actual &lt;code&gt;SQL&lt;/code&gt; that the database understands.
Note that while we usually write SQL here, the adapters don&amp;#39;t need to work with &lt;code&gt;SQL&lt;/code&gt; databases only — some adapters work just as well with no-SQL databases.
Query generation and all database communication are clearly separated from Ecto&amp;#39;s core.&lt;/p&gt;
&lt;p&gt;If you want to explore this further, try building out some complex queries with joins, subqueries, windows, etc., and see how they are represented internally — it is a great way to learn how abstractions are made inside Ecto.&lt;/p&gt;
&lt;p&gt;Finally, this query struct is converted to a SQL statement by the adapter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Ecto.Adapters.SQL.to_sql(:all, MyApp.Repo, query)
{&amp;quot;SELECT u0.\&amp;quot;name\&amp;quot; FROM \&amp;quot;users\&amp;quot; AS u0 WHERE (u0.\&amp;quot;age\&amp;quot; &amp;gt; $1)&amp;quot;, [18]}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Back to Erlang&amp;#39;s ETS Table&lt;/h3&gt;
&lt;p&gt;Back in the section about the Repo module, we created an ETS table when we started the Repository in our application.&lt;/p&gt;
&lt;p&gt;Now that ETS table comes into play.
When a query is executed multiple times, the query is only &lt;code&gt;prepared&lt;/code&gt; the first time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can learn more about &lt;a href=&quot;https://www.postgresql.org/docs/current/sql-prepare.html&quot;&gt;&lt;code&gt;PREPARE&lt;/code&gt; in the context of Postgres&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is then cached inside that ETS table and fetched from there for all subsequent calls.
To see the caching in action, check this out (notice the &lt;code&gt;:cached&lt;/code&gt; in result, which signals that this query has been cached):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; MyApp.Repo.all(query) # This puts the query in the cache

# Trying to prepare the query again gets a cached version
iex&amp;gt; Ecto.Adapter.Queryable.prepare_query(:all, MyApp.Repo, query)
{{:cached, #Function&amp;lt;41.44551318/1 in Ecto.Query.Planner.query_with_cache/8&amp;gt;,
  #Function&amp;lt;42.44551318/1 in Ecto.Query.Planner.query_with_cache/8&amp;gt;,
  {5122,
   %Postgrex.Query{
     ref: #Reference&amp;lt;0.3269063957.2912157697.165169&amp;gt;,
     name: &amp;quot;ecto_5122&amp;quot;,
     statement: &amp;quot;SELECT u0.\&amp;quot;name\&amp;quot; FROM \&amp;quot;users\&amp;quot; AS u0 WHERE (u0.\&amp;quot;age\&amp;quot; &amp;gt; $1)&amp;quot;,
     param_oids: [20],
     param_formats: [:binary],
     param_types: [Postgrex.Extensions.Int8],
     columns: [&amp;quot;name&amp;quot;],
     result_oids: [1043],
     result_formats: [:binary],
     result_types: [Postgrex.Extensions.Raw],
     types: {Postgrex.DefaultTypes, #Reference&amp;lt;0.3269063957.2912288771.132368&amp;gt;},
     cache: :reference
   }}}, [18]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this doesn’t cache the result, only the prepared statements. Prepared statements give a large performance advantage, especially for complex queries. &lt;a href=&quot;https://www.postgresql.org/docs/current/sql-prepare.html&quot;&gt;From the Postgres docs&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Prepared statements potentially have the largest performance advantage when a single session is being used to execute a large number of similar statements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The performance difference will be particularly significant if the statements are complex to plan or rewrite, e.g., if the query involves a join of many tables or requires the application of several rules.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The next important module in Ecto is the &lt;code&gt;Schema&lt;/code&gt;. Let&amp;#39;s take a look at it now.&lt;/p&gt;
&lt;h2&gt;Schema Module&lt;/h2&gt;
&lt;p&gt;You can use Ecto without schemas and it works just as well (as we saw above when we referenced the table names directly).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Schema&lt;/code&gt; module is responsible for defining and mapping a record&amp;#39;s attributes (fields and associations) from a database table to an Elixir struct.&lt;/p&gt;
&lt;p&gt;To create a schema, we write &lt;code&gt;use Ecto.Schema&lt;/code&gt; at the top of our module and use the &lt;code&gt;schema&lt;/code&gt; DSL.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Organization do
  use Ecto.Schema

  schema &amp;quot;organizations&amp;quot; do
    field :name, :string
  end
end

defmodule MyApp.User do
  use Ecto.Schema

  schema &amp;quot;users&amp;quot; do
    field :name, :string
    belongs_to :organization, MyApp.Organization
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/elixir-ecto/ecto/blob/v3.9.4/lib/ecto/schema.ex#L473&quot;&gt;&lt;code&gt;use&lt;/code&gt; statement&lt;/a&gt; includes several utility functions and macros inside the module and sets some default module attributes required for Ecto to gather data from the Schema.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/elixir-ecto/ecto/blob/v3.9.4/lib/ecto/schema.ex#L541&quot;&gt;&lt;code&gt;schema&lt;/code&gt; macro&lt;/a&gt; then updates some of those attributes to mark that this is a persisted schema (there is also another &lt;code&gt;embedded_schema&lt;/code&gt; macro to deal with non-persisted schemas) and sets some other defaults, like the primary key.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/elixir-ecto/ecto/blob/v3.9.4/lib/ecto/schema.ex#L729&quot;&gt;&lt;code&gt;field&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/elixir-ecto/ecto/blob/v3.9.4/lib/ecto/schema.ex#L1274&quot;&gt;&lt;code&gt;belongs_to&lt;/code&gt;&lt;/a&gt; inside the schema block then put those fields in the module attributes (for type validation), and add the fields to the struct defined by the module.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;Ecto.Schema&lt;/code&gt; behavior exposes some methods inside the schema to fetch field details. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(62)&amp;gt; MyApp.User.__schema__(:source)
&amp;quot;users&amp;quot;
iex(63)&amp;gt; MyApp.User.__schema__(:fields)
[:id, :name, :organization_id]
iex(64)&amp;gt; MyApp.User.__schema__(:primary_key)
[:id]
iex(65)&amp;gt; MyApp.User.__schema__(:associations)
[:organization]
iex(66)&amp;gt; MyApp.User.__schema__(:association, :organization)
%Ecto.Association.BelongsTo{
  field: :organization,
  owner: MyApp.User,
  related: MyApp.Organization,
  owner_key: :organization_id,
  related_key: :id,
  queryable: MyApp.Organization,
  on_cast: nil,
  on_replace: :raise,
  where: [],
  defaults: [],
  cardinality: :one,
  relationship: :parent,
  unique: true,
  ordered: false
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;code&gt;__schema__&lt;/code&gt; function is also the entry-point for other parts of Ecto to reflect on more details about the defined schema and perform operations on it.&lt;/p&gt;
&lt;p&gt;For example, when used as the source of a query, the repo will use schema to validate the conditions in the &lt;code&gt;where&lt;/code&gt; clause, and cast the data returned from the database to Elixir structs.
This results in much better feedback when there&amp;#39;s something wrong.&lt;/p&gt;
&lt;h2&gt;A Schema Module In Action on an Elixir App&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s try executing a query that has a typo to see the benefits of using a schema in action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;from u in &amp;quot;users&amp;quot;,
  select: u.id,
  where: u.ages &amp;gt; 19
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Executing this with &lt;code&gt;Repo.all&lt;/code&gt; will throw a generic &lt;code&gt;Postgrex.Error&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;** (Postgrex.Error) ERROR 42703 (undefined_column) column u0.ages does not exist

    query: SELECT u0.&amp;quot;id&amp;quot; FROM &amp;quot;users&amp;quot; AS u0 WHERE (u0.&amp;quot;ages&amp;quot; &amp;gt; 19)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s try the same query, but this time with a schema.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;from u in MyApp.Accounts.User,
  select: u.id,
  where: u.ages &amp;gt; 19
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As expected, this also throws an error, but it now includes the line number where it happened and has a more specific Exception type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;** (Ecto.QueryError) lib/my_app/accounts.ex:109: field `ages` in `where` does not exist in schema MyApp.Accounts.User in query:

from u0 in MyApp.Accounts.User,
  where: u0.ages &amp;gt; 19,
  select: u0.id
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works because the query planner in Ecto can look at the schema&amp;#39;s metadata and figure out that this field doesn&amp;#39;t exist on the schema even before hitting the database.&lt;/p&gt;
&lt;p&gt;Ecto also does type conversions behind the scenes when using the schema. For example, it allows us to run this query:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;id = &amp;quot;2&amp;quot;
query = from u in MyApp.Accounts.User, where: u.id == ^id
Repo.all(query)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the other hand, if you are not using a schema, a similar query will raise an exception:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;query = from u in &amp;quot;users&amp;quot;, where: u.id == ^id, select: u.id
Repo.all(query)

** (DBConnection.EncodeError) Postgrex expected an integer in -9223372036854775808..9223372036854775807, got &amp;quot;2&amp;quot;. Please make sure the value you are passing matches the definition in your table or in your query or convert the value accordingly.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Changeset Module&lt;/h2&gt;
&lt;p&gt;The final module that we will look at today is &lt;code&gt;Changeset&lt;/code&gt;.
It provides an interface for validating and transforming data before it is written into a database.&lt;/p&gt;
&lt;p&gt;Similarly to &lt;code&gt;Query&lt;/code&gt;, Changeset provides a structured way to represent changes to data. It is most commonly used with Ecto schemas, but &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#module-schemaless-changesets&quot;&gt;schemaless changesets&lt;/a&gt; are also possible when you don’t need a full-fledged schema.&lt;/p&gt;
&lt;p&gt;Ecto.Changeset provides a &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#summary&quot;&gt;comprehensive API&lt;/a&gt; to work with data.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;cast/4&lt;/code&gt; Changeset&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s start by looking at the most commonly used changeset, &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#cast/4&quot;&gt;&lt;code&gt;cast/4&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; changeset = %MyApp.User{name: &amp;quot;some name&amp;quot;}
     |&amp;gt; cast(%{&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;&amp;quot;, &amp;quot;organization_id&amp;quot; =&amp;gt; &amp;quot;1&amp;quot;, &amp;quot;foo&amp;quot; =&amp;gt; &amp;quot;bar&amp;quot;}, [:name, :organization_id])
     |&amp;gt; validate_required(:name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We pass initial data (the &lt;code&gt;MyApp.User&lt;/code&gt; struct in this case) to &lt;code&gt;cast&lt;/code&gt; followed by some parameters and the list of allowed fields.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cast&lt;/code&gt; figures out the type of each allowed field by looking at the schema metadata. &lt;code&gt;cast&lt;/code&gt; then typecasts a parameter value to an allowed value, or adds an error to the changeset.&lt;/p&gt;
&lt;p&gt;For example, here we can see that we had a value of &lt;code&gt;1&lt;/code&gt; (&lt;code&gt;String&lt;/code&gt;) as the &lt;code&gt;organization_id&lt;/code&gt;.
But from the schema, &lt;code&gt;cast&lt;/code&gt; can figure out that &lt;code&gt;organization_id&lt;/code&gt; is of type &lt;code&gt;int&lt;/code&gt; and cast the value to an integer before putting the change inside the Changeset.&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;validate_required/3&lt;/code&gt; Changeset&lt;/h3&gt;
&lt;p&gt;The second call in the pipeline, &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#validate_required/3&quot;&gt;&lt;code&gt;validate_required/3&lt;/code&gt;&lt;/a&gt;, requires the field to be present (as the name suggests).
By default, it trims any strings/binaries before running validations and assumes an empty string to be blank.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s what is printed out when you inspect the &lt;code&gt;Changeset&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;#Ecto.Changeset&amp;lt;
  action: nil,
  changes: %{organization_id: 1},
  errors: [name: {&amp;quot;can&amp;#39;t be blank&amp;quot;, [validation: :required]}],
  data: #MyApp.User&amp;lt;&amp;gt;,
  valid?: false
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This small summary already contains most of the information we need about the changeset.
It shows what changes were made to the initial data (&lt;code&gt;organization_id&lt;/code&gt; was set to &lt;code&gt;1&lt;/code&gt;), and that the changeset is invalid. It lists all the errors.&lt;/p&gt;
&lt;p&gt;Let’s go one step further and inspect the full map.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; IO.inspect(changeset, structs: false)
%{
  __struct__: Ecto.Changeset,
  action: nil,
  changes: %{organization_id: 1},
  constraints: [],
  data: %{
    __meta__: %{
      __struct__: Ecto.Schema.Metadata,
      context: nil,
      prefix: nil,
      schema: MyApp.User,
      source: &amp;quot;users&amp;quot;,
      state: :built
    },
    __struct__: MyApp.User,
    id: nil,
    name: &amp;quot;some name&amp;quot;,
    organization: %{
      __cardinality__: :one,
      __field__: :organization,
      __owner__: MyApp.User,
      __struct__: Ecto.Association.NotLoaded
    },
    organization_id: nil
  },
  empty_values: [&amp;quot;&amp;quot;],
  errors: [name: {&amp;quot;can&amp;#39;t be blank&amp;quot;, [validation: :required]}],
  filters: %{},
  params: %{&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;&amp;quot;, &amp;quot;organization_id&amp;quot; =&amp;gt; 1, &amp;quot;foo&amp;quot; =&amp;gt; &amp;quot;bar&amp;quot;},
  prepare: [],
  repo: nil,
  repo_opts: [],
  required: [:name],
  types: %{
    id: :id,
    name: :string,
    organization: {:assoc,
     %{
       __struct__: Ecto.Association.BelongsTo,
       cardinality: :one,
       defaults: [],
       field: :organization,
       on_cast: nil,
       on_replace: :raise,
       ordered: false,
       owner: MyApp.User,
       owner_key: :organization_id,
       queryable: MyApp.Organization,
       related: MyApp.Organization,
       related_key: :id,
       relationship: :parent,
       unique: true,
       where: []
     }},
    organization_id: :id
  },
  valid?: false,
  validations: []
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This contains much more information now.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;params&lt;/code&gt; are self-explanatory — the initial data and the params we fed to &lt;code&gt;cast&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;types&lt;/code&gt; contains additional data about the schema we are working with (fetched using the &lt;code&gt;__schema__&lt;/code&gt; method we saw in the previous section).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;changes&lt;/code&gt; and &lt;code&gt;errors&lt;/code&gt; are where it gets interesting. &lt;code&gt;cast&lt;/code&gt; automatically converts the string &lt;code&gt;organization_id&lt;/code&gt; to an integer because it knows that the &lt;code&gt;organization_id&lt;/code&gt; is a numeric primary key from the association details.&lt;/p&gt;
&lt;p&gt;What&amp;#39;s also interesting is that it understands that &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; is a blank value and inserts an error into the changeset from the &lt;code&gt;validate_required&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;The database manipulation functions from &lt;code&gt;Repo&lt;/code&gt; understand changesets and return errors if the changeset is invalid.&lt;/p&gt;
&lt;p&gt;The Changeset API provides several other functions for validating data and database constraints, as well as dealing with associations.&lt;/p&gt;
&lt;p&gt;These functions interact with the data and eventually update the struct that we saw above. When fed to the &lt;code&gt;Repo&lt;/code&gt; module&amp;#39;s functions, structs perform the eventual database operations.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we looked at the core concepts of the Ecto library:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We started with a &lt;code&gt;Schema&lt;/code&gt; that defined our business objects mapped to database tables.&lt;/li&gt;
&lt;li&gt;To get those objects out of the database, we used the &lt;code&gt;Query&lt;/code&gt; API.&lt;/li&gt;
&lt;li&gt;We then used &lt;code&gt;Changeset&lt;/code&gt;s to change those objects, and inserted or updated them in the database.&lt;/li&gt;
&lt;li&gt;Tying everything together was the &lt;code&gt;Repo&lt;/code&gt; module which takes inputs from all the other modules, eventually connecting to the database to fetch data or update records.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these modules work together to provide a structured and safe way to interact with databases.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.html&quot;&gt;Check out the official Ecto guide&lt;/a&gt; to integrate Ecto into your Elixir application. I have also included links to the source code in parts of this post, so feel free to go back and dig a little deeper.&lt;/p&gt;
&lt;p&gt;Until next time — happy digging!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How To Instrument Your Elixir Application with AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/01/24/how-to-instrument-your-elixir-application-with-appsignal.html"/>
    <id>https://blog.appsignal.com/2023/01/24/how-to-instrument-your-elixir-application-with-appsignal.html</id>
    <published>2023-01-24T00:00:00+00:00</published>
    <updated>2023-01-24T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s run through adding instrumentation to an Elixir application using AppSignal.</summary>
    <content type="html">&lt;p&gt;Instrumentation is an essential part of monitoring and operating an application, especially for apps heavily used in production. Even in today&amp;#39;s everchanging technology landscape, visibility and observability still challenge developers and system administrators.&lt;/p&gt;
&lt;p&gt;Metrics and logging are essential for monitoring and operating an application. Metrics measure an application&amp;#39;s performance and system health, while logging records system health and application state. Instrumentation allows us to collect metrics and log events about an application&amp;#39;s state and system health.&lt;/p&gt;
&lt;p&gt;Thanks to instrumentation, you can gain great insights into your Elixir application.&lt;/p&gt;
&lt;p&gt;In this tutorial, we will cover the importance of instrumentation, go over the basic concepts, and show you how to instrument your Elixir application with AppSignal.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Why Instrument Your Elixir Application?&lt;/h2&gt;
&lt;p&gt;Application performance monitoring (APM) is the process of monitoring and keeping track of an application&amp;#39;s performance. Many monitoring tools offer APM; in this article, we will focus on &lt;a href=&quot;https://appsignal.com/&quot;&gt;AppSignal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Out of the box, AppSignal will handle error tracking, performance monitoring, and host metrics. However, to get the most out of AppSignal, we need to instrument our application to collect metrics and log events of specific interest to us.&lt;/p&gt;
&lt;p&gt;With custom instrumentation, you can mark specific parts of an application to collect metrics and data, gaining insight into the deep inner workings of the application.&lt;/p&gt;
&lt;p&gt;For example, we can use instrumentation to collect metrics about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a specific function&amp;#39;s performance&lt;/li&gt;
&lt;li&gt;the number of times a particular function is called&lt;/li&gt;
&lt;li&gt;the performance of a specific database query&lt;/li&gt;
&lt;li&gt;the number of times a particular database query is called&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this information, developers can identify bottlenecks and refactor code to improve an application&amp;#39;s performance.&lt;/p&gt;
&lt;p&gt;Normally APM tools will not go deep into the layers of an application to collect metrics. Instead, they will collect metrics at the application level, such as the number of requests per second, the number of errors, and the average response time.&lt;/p&gt;
&lt;p&gt;But as we&amp;#39;ve discussed, custom instrumentation allows developers to manually go deep into an application&amp;#39;s layers to collect metrics and log particular events.&lt;/p&gt;
&lt;p&gt;Application performance monitoring and custom instrumentation are essential for monitoring and operating an application and should be considered complementary tools.&lt;/p&gt;
&lt;h3&gt;Pre-requisites&lt;/h3&gt;
&lt;p&gt;To follow along with this article, you will need to have the following installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elixir 1.10 or higher&lt;/li&gt;
&lt;li&gt;PostgreSQL 12 or higher&lt;/li&gt;
&lt;li&gt;Docker and Docker Compose v2 or higher&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Start by cloning the RealWorld Phoenix application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/tamanugi/realworld-phoenix.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get started, we need to install the dependencies and set up the database:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Start Database
$ docker-compose up -d

# Install dependencies
$ mix deps.get

# Create and migrate your database
$ mix ecto.setup

# Start Phoenix endpoint with `mix phx.server`
$ mix phx.server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Validate that everything works by visiting &lt;a href=&quot;http://localhost:4000/api/articles&quot;&gt;&lt;code&gt;localhost:4000/api/articles&lt;/code&gt;&lt;/a&gt; from your browser. You should be able to see the following JSON response:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
    &amp;quot;articles&amp;quot;: [
        {
            &amp;quot;author&amp;quot;: {
                &amp;quot;bio&amp;quot;: null,
                &amp;quot;following&amp;quot;: null,
                &amp;quot;image&amp;quot;: null,
                &amp;quot;username&amp;quot;: &amp;quot;username&amp;quot;
            },
            &amp;quot;body&amp;quot;: &amp;quot;It takes a Jacobian&amp;quot;,
            &amp;quot;createdAt&amp;quot;: &amp;quot;2022-11-06T17:43:38.000Z&amp;quot;,
            &amp;quot;description&amp;quot;: &amp;quot;Ever wonder how?&amp;quot;,
            &amp;quot;favorited&amp;quot;: null,
            &amp;quot;favoritesCount&amp;quot;: 0,
            &amp;quot;slug&amp;quot;: &amp;quot;how-to-train-your-dragon-1&amp;quot;,
            &amp;quot;tagList&amp;quot;: [
                &amp;quot;dragons&amp;quot;,
                &amp;quot;training&amp;quot;
            ],
            &amp;quot;title&amp;quot;: &amp;quot;How to train your dragon 1&amp;quot;,
            &amp;quot;updatedAt&amp;quot;: &amp;quot;2022-11-06T17:43:38.000Z&amp;quot;
        },
...
    ],
    &amp;quot;articlesCount&amp;quot;: 10
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, &lt;a href=&quot;https://appsignal.com/users/sign_up&quot;&gt;sign up for a free trial of AppSignal&lt;/a&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Once you have an AppSignal account, attach the AppSignal Elixir package to your application by adding the following to your &lt;code&gt;mix.exs&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
def deps do
  [
      {:appsignal_phoenix, &amp;quot;~&amp;gt; 2.0&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make sure you install the dependency by running &lt;code&gt;mix deps.get&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next, configure AppSignal by running the following mix command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix appsignal.install YOUR_PUSH_API_KEY
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: YOUR_PUSH_API_KEY is the Push API Key for your AppSignal account. You can find your Push API Key in your AppSignal account under Settings &amp;gt; API Keys.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Follow the automated installation instructions and make sure you use the defaults. Then take one more step to capture the Phoenix HTTP requests. Open the &lt;code&gt;endpoint.ex&lt;/code&gt; file and add &lt;code&gt;Appsignal.Phoenix&lt;/code&gt; to the list of modules:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  # lib/realworld_phoenix_web/endpoint.ex
defmodule AppsignalPhoenixExampleWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :appsignal_phoenix_example
  use Appsignal.Phoenix

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start the application again with &lt;code&gt;mix phx.server&lt;/code&gt;, and make a couple of requests to the application by visiting &lt;a href=&quot;http://localhost:4000/api/articles&quot;&gt;&lt;code&gt;localhost:4000/api/articles&lt;/code&gt;&lt;/a&gt; from your browser.&lt;/p&gt;
&lt;p&gt;If the setup is successful, you should be able to see the requests in your AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/dashboard.png&quot; alt=&quot;Dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Here, we can see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the number of requests per second&lt;/li&gt;
&lt;li&gt;the number of errors&lt;/li&gt;
&lt;li&gt;the average response time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As well as the default metrics, we can also see some custom metrics. Let&amp;#39;s add custom metrics in the next section.&lt;/p&gt;
&lt;h2&gt;Custom Instrumentation for Your Elixir App&lt;/h2&gt;
&lt;p&gt;Now that we have AppSignal set up, let&amp;#39;s implement some custom instrumentation. For this example, we will instrument the &lt;code&gt;lib/realworld_phoenix_web/controllers/article_controller.ex/index/0&lt;/code&gt; function to collect metrics on the number of times the function is called and the average response time.&lt;/p&gt;
&lt;h2&gt;Key Instrumentation Concepts&lt;/h2&gt;
&lt;p&gt;Before we proceed any further, let&amp;#39;s quickly go over some key concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Instrumentation&lt;/strong&gt; is the process of adding observability code to our application. This code will collect metrics and log events of specific interest to us.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trace:&lt;/strong&gt; The record of the paths taken by a single request through the application. Tracing makes debugging less daunting by breaking down a request as the application processes it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Span:&lt;/strong&gt; Spans are the building blocks of traces, representing a single unit of work or operation within a system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are two ways to instrument our application. The first uses helper functions, and the second uses function decorators. We&amp;#39;ll review both approaches, starting with the helper function approach.&lt;/p&gt;
&lt;h2&gt;Instrumentation Using Helper Functions for Your Elixir App&lt;/h2&gt;
&lt;p&gt;Using decorators to add custom instrumentation is relatively easy. However, there are cases where we might need more flexibility with instrumentation — for example, when we want to trace specific parts of a function.&lt;/p&gt;
&lt;p&gt;Using the &lt;code&gt;index/2&lt;/code&gt; function as an example, we can use helper functions to add custom instrumentation. Open the &lt;code&gt;lib/realworld_phoenix_web/controllers/article_controller.ex&lt;/code&gt; file and update the code to look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/realworld_phoenix_web/controllers/article_controller.ex
def index(conn, params) do
  # Add a delay to the function
  slow()

  keywords =  Appsignal.instrument(&amp;quot;keywords_map&amp;quot;, fn -&amp;gt;
    for {key, val} &amp;lt;- params, do: {String.to_atom(key), val}
  end)

  keywords = Appsignal.instrument(&amp;quot;keywords&amp;quot;, fn -&amp;gt;

      case Guardian.Plug.current_resource(conn) do
          nil -&amp;gt; keywords
          user -&amp;gt; keywords |&amp;gt; Keyword.put(:user, user)
      end
  end)

  articles = Appsignal.instrument(&amp;quot;articles&amp;quot;, fn -&amp;gt;
      Articles.list_articles(keywords)
      |&amp;gt; Articles.article_preload()
  end)

  render(conn, &amp;quot;index.json&amp;quot;, articles: articles)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the &lt;code&gt;Appsignal.instrument/2&lt;/code&gt; function, we can wrap specific parts of the code and add events to the &lt;a href=&quot;https://opentelemetry.io/docs/concepts/signals/traces/#spans-in-opentelemetry&quot;&gt;span&lt;/a&gt;. This allows us to break down the transaction into smaller parts and see where an application is spending most of its time.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Appsignal.instrument/2&lt;/code&gt; allows us to instrument a function, taking three parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;name of the function&lt;/li&gt;
&lt;li&gt;category (this can be left empty)&lt;/li&gt;
&lt;li&gt;the function we are trying to instrument itself&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Instrumenting Your Elixir App with the Function Decorator&lt;/h2&gt;
&lt;p&gt;The main advantage of function decorators is that we can instrument our application without modifying the code. For this app, we can use &lt;code&gt;Appsignal.Instrumentation.Decorators&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Open the &lt;code&gt;lib/realworld_phoenix_web/controllers/article_controller.ex&lt;/code&gt; file and add the following to the top of the file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/realworld_phoenix_web/controllers/article_controller.ex
use Appsignal.Instrumentation.Decorators
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, to make this example more interesting, let&amp;#39;s add a delay to the &lt;code&gt;index/0&lt;/code&gt; function. This will allow us to see the impact of the delay on the response time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/realworld_phoenix_web/controllers/article_controller.ex
def index(conn, params) do
  # Add a delay to the function
  slow()
  keywords = for {key, val} &amp;lt;- params, do: {String.to_atom(key), val}

  keywords =
    case Guardian.Plug.current_resource(conn) do
      nil -&amp;gt; keywords
      user -&amp;gt; keywords |&amp;gt; Keyword.put(:user, user)
    end

  articles =
    Articles.list_articles(keywords)
    |&amp;gt; Articles.article_preload()

  render(conn, &amp;quot;index.json&amp;quot;, articles: articles)
end

# Decorate this function to add custom instrumentation
@decorate transaction_event()
defp slow do
  Enum.random(1000..6000)
  |&amp;gt;:timer.sleep()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have added the decorator, let&amp;#39;s make a couple of requests to our application. You can do this by visiting &lt;a href=&quot;http://localhost:4000/api/articles&quot;&gt;&lt;code&gt;localhost:4000/api/articles&lt;/code&gt;&lt;/a&gt; from your browser.&lt;/p&gt;
&lt;p&gt;After refreshing the articles a couple of times, you should be able to see the following in your AppSignal dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/dashboard-2.png&quot; alt=&quot;Dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We can see that the &lt;code&gt;index/0&lt;/code&gt; function was called and is reporting a mean of 5.1 seconds. If we click on the dashboard, we can check out the transaction details:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/transaction.png&quot; alt=&quot;Transaction&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Here, there&amp;#39;s information about how much time the transaction spent calling the database, parsing the route, etc. Because we added custom instrumentation, we know that the &lt;code&gt;slow/0&lt;/code&gt; function is the bottleneck.&lt;/p&gt;
&lt;h2&gt;Helper Vs. Decorator Functions&lt;/h2&gt;
&lt;p&gt;When it comes to choosing between decorators and helper functions, it really depends on your use case. Both approaches have their advantages and disadvantages.&lt;/p&gt;
&lt;p&gt;Decorators are great for adding instrumentation to a function without having to modify the code. However, we can&amp;#39;t add instrumentation to specific parts of the function and that might limit the amount of information we can gather. Yet, in cases where functions are fairly simple, decorators are a great way to add instrumentation without impacting on code.&lt;/p&gt;
&lt;p&gt;Helper functions, on the other hand, allow us to add instrumentation to specific parts of a function. With decorators, we can only add instrumentation to an entire function. But with helpers, we can add another layer of granularity to dig deeper into potential bottlenecks in our application. Going back to our example above, we were able to break down the &lt;code&gt;index/0&lt;/code&gt; function into smaller parts and see where the application was spending most of its time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/event-timeline.png&quot; alt=&quot;Event Timeline with Helper Functions&quot;/&gt;&lt;/p&gt;
&lt;p&gt;However, helper functions require us to modify the code, which might not be ideal in some cases and can add complexity.&lt;/p&gt;
&lt;p&gt;Most importantly, consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;your use case&lt;/li&gt;
&lt;li&gt;the amount of information you want to gather&lt;/li&gt;
&lt;li&gt;how much granularity you need in your instrumentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In most cases, helper functions will be the best approach, as they can add a significant amount of granularity to your trace.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this article, we went over the basics of adding instrumentation to an Elixir application. We learned how instrumentation can help us uncover bottlenecks and improve an application&amp;#39;s performance. We also saw how &lt;a href=&quot;https://appsignal.com/&quot;&gt;AppSignal&lt;/a&gt; can help us aggregate and visualize the data we collect.&lt;/p&gt;
&lt;p&gt;With AppSignal, we have a single tool that allows us to collect different data types, and explore the data to look for bottlenecks, issues, and potential correlations between different parts of a system.&lt;/p&gt;
&lt;p&gt;Instrumentation is a powerful tool that will help you understand the inner workings of your application. You will be armed with the knowledge to resolve bottlenecks and catch potential issues before they become a problem.&lt;/p&gt;
&lt;p&gt;Happy instrumenting!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Debugging and Tracing in Erlang</title>
    <link rel="alternate" href="https://blog.appsignal.com/2023/01/10/debugging-and-tracing-in-erlang.html"/>
    <id>https://blog.appsignal.com/2023/01/10/debugging-and-tracing-in-erlang.html</id>
    <published>2023-01-10T00:00:00+00:00</published>
    <updated>2023-01-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second and final part of this two-part series, we&#039;ll dive into Erlang tools you can use for debugging.</summary>
    <content type="html">&lt;p&gt;In part one of this series, the debugging tools we used — Elixir&amp;#39;s &lt;code&gt;IO.inspect/2&lt;/code&gt;, &lt;code&gt;IEx.pry&lt;/code&gt;, and &lt;code&gt;dbg/2&lt;/code&gt; — required us to insert changes into
code directly. Outside the development environment, you probably won&amp;#39;t (and shouldn&amp;#39;t) have access to your code.&lt;/p&gt;
&lt;p&gt;Erlang has a few tools to debug code at runtime: &lt;code&gt;:debugger&lt;/code&gt;, &lt;code&gt;:dbg.tracer&lt;/code&gt;, and &lt;code&gt;:observer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s look at the
&lt;a href=&quot;https://www.erlang.org/doc/man/dbg.html&quot;&gt;&lt;code&gt;:debugger&lt;/code&gt;&lt;/a&gt;, a graphical debugging
tool.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Debugging Runtime with &lt;code&gt;:debugger&lt;/code&gt; in Erlang&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Side note&lt;/strong&gt;: While &lt;code&gt;:debugger&lt;/code&gt; has a graphical interface, Erlang also provides
&lt;a href=&quot;https://www.erlang.org/doc/man/dbg.html&quot;&gt;&lt;code&gt;:dbg&lt;/code&gt;&lt;/a&gt;. That&amp;#39;s a debugging tool as well,
but it uses a text-based interface you can run directly on &lt;code&gt;IEx&lt;/code&gt; to achieve
the same results.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The very first thing that we need to do is to start the debugger. To do that,
we simply call &lt;code&gt;:debugger.start/0&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; :debugger.start()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll be presented with the debugger graphical interface:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/debugger.png&quot; alt=&quot;Debugger Graphical Interface&quot;/&gt;&lt;/p&gt;
&lt;p&gt;However, to start debugging, we need to tell Erlang&amp;#39;s interpreter
&lt;em&gt;where&lt;/em&gt; to stop.&lt;/p&gt;
&lt;p&gt;We can interact with the interpreter using the
&lt;a href=&quot;https://www.erlang.org/doc/man/int.html&quot;&gt;&lt;code&gt;:int&lt;/code&gt;&lt;/a&gt; module. We&amp;#39;ll use two
functions: &lt;a href=&quot;https://www.erlang.org/doc/man/int.html#ni-1&quot;&gt;&lt;code&gt;:int.ni/1&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://www.erlang.org/doc/man/int.html#break-2&quot;&gt;&lt;code&gt;:int.break/2&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:int.ni/1&lt;/code&gt; tells the interpreter to go over all nodes and
interpret the given module, while &lt;code&gt;:int.break/2&lt;/code&gt; adds a breakpoint in the given line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Tell the interpreter to interpret the given module
iex&amp;gt; :int.ni(Messenger.IExClient)
{:module, Messenger.IExClient}
# Add a breakpoint at line 78
iex&amp;gt; :int.break(Messenger.IExClient, 78)
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when we try to call the &lt;code&gt;msg/2&lt;/code&gt; function, our code will pause the execution,
and the debugger interface will update:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/debugger-paused.png&quot; alt=&quot;Debugger Graphical Interface Paused at Line 78&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Clicking twice on the breakpoint will open another window, so we can see the
exact line of code where execution is paused. In this same window, we can also view all variables in the current execution context (like we did
with &lt;code&gt;IEx.pry&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;As this is an Erlang tool, it will show the variables from Elixir code in a
weird way. Erlang doesn&amp;#39;t allow variables to be reassigned. The Elixir compiler has a trick to allow that: variables have versions.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take the following Erlang snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;Name = &amp;quot;Jake&amp;quot;,
Name2 = string:uppercase(Name).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note how we have to create another variable to store the result of
&lt;code&gt;string:uppercase(Name)&lt;/code&gt;. We can write this code in Elixir as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;name = &amp;quot;Jake&amp;quot;
name = String.upcase(name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Behind the scenes, the compiler will automatically version this variable for us.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;_name@1 = &amp;quot;Jake&amp;quot;
_name@2 = String.upcase(_name@1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s how we see Elixir variables in the debugger window.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/debugger-line78.png&quot; alt=&quot;Debugger Graphical Interface Showing The Code&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We can add breakpoints at any point in our code and inspect what
happens on function calls, loops, recursive functions, etc. And the good
thing is that we don&amp;#39;t need to modify any lines of code as we did with
&lt;code&gt;IO.inspect&lt;/code&gt;, &lt;code&gt;IEX.pry&lt;/code&gt;, and &lt;code&gt;dbg/2&lt;/code&gt; — but we still need the code to be
available.&lt;/p&gt;
&lt;p&gt;In the next section, we&amp;#39;ll learn about tracing: a way to debug applications at
runtime without modifying or having access to the source code.&lt;/p&gt;
&lt;h2&gt;Tracing (Distributed) Elixir Applications&lt;/h2&gt;
&lt;p&gt;So far, we&amp;#39;ve learned how to inspect and debug code and modules. However, sometimes
we need to go even further.&lt;/p&gt;
&lt;p&gt;Tracing an application means you can track an event starting in one
function and follow its execution all the way down into the execution chain —
even across the network.&lt;/p&gt;
&lt;p&gt;Erlang provides different tools to do that. We&amp;#39;ll look into
&lt;a href=&quot;https://www.erlang.org/doc/man/dbg.html#tracer-0&quot;&gt;&lt;code&gt;:dbg.tracer&lt;/code&gt;&lt;/a&gt; (which is text-based)
to learn the basics of tracing. Then, we&amp;#39;ll use &lt;code&gt;Trace Overview&lt;/code&gt; in &lt;a href=&quot;https://www.erlang.org/doc/apps/observer/observer_ug.html&quot;&gt;&lt;code&gt;:observer&lt;/code&gt;&lt;/a&gt;
(a graphical interface) to trace applications.&lt;/p&gt;
&lt;h2&gt;Traces with &lt;code&gt;:dbg.tracer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Because we won&amp;#39;t use the source code to tell the debugger where to stop, to get the tracer working, we need to set up a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start Erlang&amp;#39;s debugger&lt;/li&gt;
&lt;li&gt;Start the tracer process&lt;/li&gt;
&lt;li&gt;Select which nodes should be monitored (when in clusters)&lt;/li&gt;
&lt;li&gt;Tell the tracer which processes it should monitor&lt;/li&gt;
&lt;li&gt;Tell the tracer how to detect a function call that should be traced&lt;/li&gt;
&lt;/ul&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;First, let&amp;#39;s start the debugger and tracer processes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Start the debugger
iex&amp;gt; :dbg.start()
# Start the tracer
iex&amp;gt; :dbg.tracer()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For now, the tracer will only listen to the local node. We&amp;#39;ll change this
later.&lt;/p&gt;
&lt;p&gt;To configure the process to listen to, we&amp;#39;ll use &lt;code&gt;:dbg.p/2&lt;/code&gt; (&lt;code&gt;p&lt;/code&gt;
stands for process). To keep things simple, we&amp;#39;ll listen to all processes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# listen to all processes
iex&amp;gt; :dbg.p(:all, :c)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to give the tracer some function call &lt;em&gt;patterns&lt;/em&gt; to
monitor. To do that, we need &lt;a href=&quot;https://www.erlang.org/doc/apps/erts/match_spec.html&quot;&gt;&lt;em&gt;function match
specs&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Match specs alone require an entire post to explain. To keep it short,
think of them as a &lt;em&gt;regex&lt;/em&gt; for functions. You can match function calls with
specific values and returns, which can be very useful when debugging a problem.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;match pattern&lt;/em&gt; we&amp;#39;ll use here, &lt;code&gt;[]&lt;/code&gt;, says that we don&amp;#39;t care
about the values passed as an argument. Using
&lt;a href=&quot;https://www.erlang.org/doc/man/dbg.html#fun2ms-1&quot;&gt;&lt;code&gt;:dbg.fun2ms&lt;/code&gt;&lt;/a&gt;, you can write
the pattern as a function, and it will generate the match spec for you.&lt;/p&gt;
&lt;p&gt;To identify the &lt;em&gt;function&lt;/em&gt; to debug, use
&lt;a href=&quot;https://www.erlang.org/doc/man/dbg.html#tp-4&quot;&gt;&lt;code&gt;:dbg.tpl/4&lt;/code&gt;&lt;/a&gt;. &lt;code&gt;tpl&lt;/code&gt; stands for trace pattern local.&lt;/p&gt;
&lt;p&gt;In this example, we&amp;#39;ll match all GenServer callbacks that
&lt;code&gt;Messaging.MessengerServer&lt;/code&gt; implemented:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; :dbg.tpl(Messaging.MessengerServer, :handle_call, 3, [])
iex&amp;gt; :dbg.tpl(Messaging.MessengerServer, :handle_cast, 2, [])
iex&amp;gt; :dbg.tpl(Messaging.MessengerServer, :handle_info, 2, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, whenever we interact with the messenger functions, we&amp;#39;ll be notified
that it was called:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; sign in &amp;quot;alice&amp;quot;
Signed in!
(&amp;lt;0.159.0&amp;gt;) call &amp;#39;Elixir.Messenger.MessagingServer&amp;#39;:handle_call({sign_in,&amp;lt;&amp;lt;&amp;quot;alice&amp;quot;&amp;gt;&amp;gt;,nil},{&amp;lt;0.160.0&amp;gt;,[alias|#Ref&amp;lt;0.3934582249.1729953800.172958&amp;gt;]},nil)
:ok
iex&amp;gt; msg &amp;quot;bob&amp;quot;, &amp;quot;hello!&amp;quot;
Message sent!
(&amp;lt;0.159.0&amp;gt;) call &amp;#39;Elixir.Messenger.MessagingServer&amp;#39;:handle_call({send,&amp;lt;&amp;lt;&amp;quot;bob&amp;quot;&amp;gt;&amp;gt;,&amp;lt;&amp;lt;&amp;quot;hello!&amp;quot;&amp;gt;&amp;gt;},{&amp;lt;0.160.0&amp;gt;,[alias|#Ref&amp;lt;0.3934582249.1729953796.173763&amp;gt;]},#{inbox =&amp;gt; [],notify_fun =&amp;gt; nil,sent =&amp;gt; [],user =&amp;gt; &amp;lt;&amp;lt;&amp;quot;alice&amp;quot;&amp;gt;&amp;gt;})
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We don&amp;#39;t need to edit code, load modules, or add breakpoints. The Erlang
tracer detects function calls that match our rules and automatically traces
them for us.&lt;/p&gt;
&lt;p&gt;The log prints, but it is not Elixir-friendly because this tool was
designed with Erlang code in mind. However, we can give the tracer a custom
function to handle traces. With this function, we can translate the trace
information into something that makes more sense to an Elixir developer.&lt;/p&gt;
&lt;p&gt;This function will be called for all traces and given the trace information
that should be handled, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;caller pid&lt;/li&gt;
&lt;li&gt;module name&lt;/li&gt;
&lt;li&gt;function name&lt;/li&gt;
&lt;li&gt;function
arguments&lt;/li&gt;
&lt;li&gt;timestamp&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; # Custom trace handler
iex&amp;gt; handler = fn data, trace_name -&amp;gt;
...&amp;gt;  case data do
...&amp;gt;    {_, pid, _, {module, fun, args}, timestamp} -&amp;gt;
...&amp;gt;      {{y, mm, d}, {h, m, s}} =  :calendar.now_to_datetime(timestamp)
...&amp;gt;      arg_list = Enum.map(args, &amp;amp;inspect/1)
...&amp;gt;
...&amp;gt;      IO.puts(&amp;quot;#{trace_name} :: [#{y}-#{mm}-#{d} #{h}:#{m}:#{s}] (#{inspect(pid)}) #{inspect(module)}.#{fun}(#{Enum.join(arg_list, &amp;quot;, &amp;quot;)})&amp;quot;)
...&amp;gt;  end
...&amp;gt; end

# Start tracer with the custom function
iex&amp;gt; :dbg.tracer(:process, {handler, &amp;quot;Initial Data&amp;quot;})
# Include timestamps on traces
iex&amp;gt; :dbg.p(:all, [:call, :timestamp])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, the custom function is not pretty, but it does the job. We have to convert
the timestamp from Erlang format to a readable string, and the arg list has to be
transformed so we can read the values.&lt;/p&gt;
&lt;p&gt;But now, the logged trace looks like it&amp;#39;s
coming from an Elixir application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Initial Trace :: [2022-10-20 12:56:48] (#PID&amp;lt;18901.161.0&amp;gt;) Messenger.MessagingServer.handle_call({:sign_in, &amp;quot;bob&amp;quot;, nil}, {#PID&amp;lt;18901.162.0&amp;gt;, [:alias | #Reference&amp;lt;18901.2941783407.3368878085.222214&amp;gt;]}, nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we know the important concepts around tracing, let&amp;#39;s do this in a cluster!&lt;/p&gt;
&lt;h2&gt;Remote Nodes&lt;/h2&gt;
&lt;p&gt;So far, we have worked with the local node, but our &lt;code&gt;messenger&lt;/code&gt; application is
designed to run in a cluster.&lt;/p&gt;
&lt;p&gt;By tracing remote nodes, we can view everything that happens —
from the moment we send a message in a local node to when it
reaches the remote node.&lt;/p&gt;
&lt;p&gt;The good news is that we already know most of what&amp;#39;s required to do that.
We just need to tell the tracer to monitor other nodes
using &lt;code&gt;:dbg.n&lt;/code&gt; (&lt;code&gt;n&lt;/code&gt; stands for node).&lt;/p&gt;
&lt;p&gt;To monitor the whole cluster, we iterate over the list of nodes
and call &lt;code&gt;:dbg.n/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; [Node.self() | Node.list()] |&amp;gt; Enum.each(&amp;amp;:dbg.n/1)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Putting it All Together: A Script that Runs a Tracer&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s create a script that will automatically set up a tracer for us:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# tracer.exs

# Custom trace handler
handler = fn data, trace_name -&amp;gt;
  case data do
    {_, pid, _, {module, fun, args}, timestamp} -&amp;gt;
      {{y, mm, d}, {h, m, s}} =  :calendar.now_to_datetime(timestamp)
      arg_list = Enum.map(args, &amp;amp;inspect/1)

      IO.puts(&amp;quot;#{trace_name} :: [#{y}-#{mm}-#{d} #{h}:#{m}:#{s}] (#{inspect(pid)}) #{inspect(module)}.#{fun}(#{Enum.join(arg_list, &amp;quot;, &amp;quot;)})&amp;quot;)
  end
end

# Start the debugger process
:dbg.start()

# Start the tracer process
:dbg.tracer(:process, {handler, &amp;quot;Initial Trace&amp;quot;})

# Tell the tracer to monitor all nodes
[Node.self() | Node.list()] |&amp;gt; Enum.each(&amp;amp;:dbg.n/1)

# Tell the tracer to monitor all processes and include a timestamp
:dbg.p(:all, [:call, :timestamp])

# Tell the tracer the function pattern to monitor
:dbg.tpl(Messenger.MessagingServer, :handle_call, 3, [])
:dbg.tpl(Messenger.MessagingServer, :handle_cast, 2, [])
:dbg.tpl(Messenger.MessagingServer, :handle_info, 2, [])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To see it in action, let&amp;#39;s start another node with &lt;code&gt;./start dbg&lt;/code&gt; that will just
print the trace logs. Load the script above with &lt;code&gt;c &amp;quot;tracer.exs&amp;quot;&lt;/code&gt; on iex:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ ./start dbg
iex&amp;gt; c &amp;quot;tracer.exs&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new node will see all messages exchanged between &lt;code&gt;node0&lt;/code&gt; and
&lt;code&gt;node1&lt;/code&gt;, as well as all internal calls:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;# alice signs in
Initial Trace :: [2022-10-13 4:42:59] (#PID&amp;lt;18901.159.0&amp;gt;) Messenger.MessagingServer.handle_call({:sign_in, &amp;quot;alice&amp;quot;, nil}, {#PID&amp;lt;18901.160.0&amp;gt;, [:alias | #Reference&amp;lt;18901.3988451517.2270494721.161681&amp;gt;]}, nil)

# bob signing in
ok :: [2022-10-13 4:43:8] (#PID&amp;lt;19318.159.0&amp;gt;) Messenger.MessagingServer.handle_call({:sign_in, &amp;quot;bob&amp;quot;, nil}, {#PID&amp;lt;19318.160.0&amp;gt;, [:alias | #Reference&amp;lt;19318.2685074897.123797505.34702&amp;gt;]}, nil)

# alice sends &amp;quot;Hello!&amp;quot; to bob
ok :: [2022-10-13 4:43:42] (#PID&amp;lt;18901.159.0&amp;gt;) Messenger.MessagingServer.handle_call({:send, &amp;quot;bob&amp;quot;, &amp;quot;Hello!&amp;quot;}, {#PID&amp;lt;18901.160.0&amp;gt;, [:alias | #Reference&amp;lt;18901.3988451517.2270494721.161694&amp;gt;]}, %{inbox: [], notify_fun: nil, sent: [], user: &amp;quot;alice&amp;quot;})

# bob receives &amp;quot;Hello!&amp;quot; from alice
ok :: [2022-10-13 4:43:42] (#PID&amp;lt;19318.159.0&amp;gt;) Messenger.MessagingServer.handle_info({:msg, &amp;quot;alice&amp;quot;, &amp;quot;Hello!&amp;quot;}, %{inbox: [], notify_fun: nil, sent: [], user: &amp;quot;bob&amp;quot;})

# bob opens its inbox
ok :: [2022-10-13 4:43:52] (#PID&amp;lt;19318.159.0&amp;gt;) Messenger.MessagingServer.handle_call(:inbox, {#PID&amp;lt;19318.160.0&amp;gt;, [:alias | #Reference&amp;lt;19318.2685074897.123797505.34749&amp;gt;]}, %{inbox: [{&amp;quot;alice&amp;quot;, &amp;quot;Hello!&amp;quot;}], notify_fun: nil, sent: [], user: &amp;quot;bob&amp;quot;})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By tweaking the trace handler function and the &lt;em&gt;match specs&lt;/em&gt;, we can design powerful tracing scripts to see everything that happens in our application.&lt;/p&gt;
&lt;h2&gt;The &lt;code&gt;:observer&lt;/code&gt; in Erlang&lt;/h2&gt;
&lt;p&gt;This is another valuable tool with a graphical interface included in
Erlang. We can access it from &lt;code&gt;iex&lt;/code&gt; by simply typing &lt;code&gt;:observer.start&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/observer.png&quot; alt=&quot;Observer Graphical Monitoring Tool&quot;/&gt;&lt;/p&gt;
&lt;p&gt;There is a lot of information here, and you can even see stats from other nodes!&lt;/p&gt;
&lt;h2&gt;Trace Overview in &lt;code&gt;:observer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned, &lt;code&gt;:dbg&lt;/code&gt; is a text-based tool for debugging and tracing. But it&amp;#39;s
also possible to do the same thing using the &amp;quot;Trace Overview&amp;quot; in
&lt;code&gt;:observer&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/observer-trace.png&quot; alt=&quot;Trace Overview&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And the steps are the same: select nodes, select processes, and add match specs.&lt;/p&gt;
&lt;p&gt;Once you have this configured, hit &lt;code&gt;Start Trace&lt;/code&gt; to view the trace logs
in a new window:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/observer-trace-logs.png&quot; alt=&quot;Trace Logs Window&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Debugging Production Apps with AppSignal&lt;/h2&gt;
&lt;p&gt;AppSignal offers an &lt;a href=&quot;https://docs.appsignal.com/elixir/integrations/erlang.html&quot;&gt;integration for Erlang&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After you deploy your application to production, AppSignal can help monitor and debug errors from the real world too. You can set it up for your app easily and painlessly — once installed, you&amp;#39;ll immediately gain access to the main dashboard, which includes error tracking, alongside &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;some other great features&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Set up alerts, and you&amp;#39;ll be instantly notified when errors occur.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/erlang-errors-dashboard.png&quot; alt=&quot;Erlang errors dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can drill down to see the root causes of errors and easily fix them from there:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-01/erlang-error-details.png&quot; alt=&quot;Erlang error details&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;Read more about AppSignal for Elixir&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In both parts of this series, we put the most important Elixir and Erlang debugging tools into action (with the help of our demo project).&lt;/p&gt;
&lt;p&gt;From Elixir&amp;#39;s simple &lt;code&gt;IO.inspect/2&lt;/code&gt; to Erlang&amp;#39;s powerful tracer, the Erlang ecosystem has
tools for all kinds of debugging scenarios. We can use these tools seamlessly, whether locally or in a
distributed system.&lt;/p&gt;
&lt;p&gt;Happy debugging!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>AppSignal’s Top 5 Elixir posts in 2022</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/12/21/appsignal’s-top-5-elixir-posts-in-2022.html"/>
    <id>https://blog.appsignal.com/2022/12/21/appsignal’s-top-5-elixir-posts-in-2022.html</id>
    <published>2022-12-21T00:00:00+00:00</published>
    <updated>2022-12-21T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s look at the top 5 most liked Elixir blog posts from 2022!</summary>
    <content type="html">&lt;p&gt;With the holidays approaching, the AppSignal team is taking a mini winter break from publishing Elixir posts. We hope to bring you a lot more of them in 2023. 🍵 ❄️&lt;/p&gt;
&lt;p&gt;In the meantime, let&amp;#39;s look at the top 5 most liked Elixir blog posts from 2022!&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://blog.appsignal.com/2022/02/08/functional-programming-in-elixir-with-witchcraft.html&quot;&gt;Functional Programming in Elixir with Witchcraft&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While Elixir is a functional programming language, it is different from most of the other popular functional languages like Haskell, Scala, OCaml, and F#.&lt;/p&gt;
&lt;p&gt;In this article, I want to introduce you to a library called Witchcraft and show how you can use it to emulate Haskell-style programming in Elixir.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://blog.appsignal.com/2022/05/31/algebraic-data-types-in-elixir.html&quot;&gt;Algebraic Data Types in Elixir&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Elixir is a dynamically-typed language. Types in Elixir are checked when a program runs, not when it compiles. If they don’t match up, an exception is thrown.&lt;/p&gt;
&lt;p&gt;In statically-typed languages, types are checked during compile time. This can help us write code that is correct, understandable, and refactorable.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll cover Dialyzer, ADTs, and how you can solve the problem of illegal states by using them together.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://blog.appsignal.com/2022/05/10/a-guide-to-event-driven-architecture-in-elixir.html&quot;&gt;A Guide to Event-Driven Architecture in Elixir&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this post, we will explore how event-driven architecture can make your app more responsive for users and decouple your modules for a better developer experience.&lt;/p&gt;
&lt;p&gt;We will also look at several methods of implementing event-driven architecture with Elixir. Elixir is particularly good for this because of the advanced and concise message-passing APIs that it offers and BEAM&amp;#39;s outstanding support for concurrency.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;&lt;a href=&quot;https://blog.appsignal.com/2022/05/24/livebook-for-elixir-just-what-the-docs-ordered.html&quot;&gt;Livebook for Elixir: Just What the Docs Ordered&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While initially conceived as a tool for data exploration (much like Jupyter for Python), Livebook has deservedly become a sensation in the Elixir community.&lt;/p&gt;
&lt;p&gt;It has been fantastic to see all the wonderful ways teams are leveraging Livebook for a range of different use cases. We have seen Livebooks being used to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create interactive documentation for libraries.&lt;/li&gt;
&lt;li&gt;Build onboarding material and guides.&lt;/li&gt;
&lt;li&gt;Audit and explore potential dependencies in your app.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;https://blog.appsignal.com/2022/07/26/how-to-write-a-functor-in-elixir.html&quot;&gt;How to Write a Functor in Elixir&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this post, I will introduce you to a concept from functional programming called a functor. We’ll make a &lt;code&gt;Functor&lt;/code&gt; protocol with a function called &lt;code&gt;fmap&lt;/code&gt; that will aspire to be a better version of &lt;code&gt;Enum.map&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;AFK Time!&lt;/h2&gt;
&lt;p&gt;We hope you&amp;#39;ve learned something new while reading our blog this year. We know we have! In 2023, our team will continue working hard to publish new blog posts in our efforts to spread knowledge across the Elixir community.&lt;/p&gt;
&lt;p&gt;Wherever you are in the world, we hope you enjoy a happy and healthy end of year. We hope that 2023 will be an amazing year for you, with no bugs and packed with events and adventures that are almost as sweet as a stroopwafel.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Cache Locally in Elixir with Nebulex</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/12/13/how-to-cache-locally-in-elixir-with-nebulex.html"/>
    <id>https://blog.appsignal.com/2022/12/13/how-to-cache-locally-in-elixir-with-nebulex.html</id>
    <published>2022-12-13T00:00:00+00:00</published>
    <updated>2022-12-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how you can use Nebulex to cache data locally in your Elixir application.</summary>
    <content type="html">&lt;p&gt;In an Elixir application, you might need to access certain data frequently, which can be costly. The access time involved in retrieving data at every step can cause high latency, or even make the application crash (due to an increased workload on the database).&lt;/p&gt;
&lt;p&gt;Caching is the best technique to store the most frequently accessed data and minimize database data retrieval, improving the overall performance of the application.&lt;/p&gt;
&lt;p&gt;In this post, you&amp;#39;ll learn how to use the &lt;a href=&quot;https://github.com/cabol/nebulex&quot;&gt;Nebulex&lt;/a&gt; caching toolkit to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cache locally in your Elixir applications&lt;/li&gt;
&lt;li&gt;get familiar with different supported caching solutions/strategies&lt;/li&gt;
&lt;li&gt;see how Nebulex can be a good fit for caching&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;What Is Nebulex?&lt;/h2&gt;
&lt;p&gt;You&amp;#39;ve likely already come across some caching options for your existing Elixir application.&lt;/p&gt;
&lt;p&gt;Here, I will introduce you to the Nebulex caching toolkit. Nebulex is an &lt;em&gt;in-memory and distributed caching framework for Elixir&lt;/em&gt; that supports temporarily storing and accessing data in an Elixir application.&lt;/p&gt;
&lt;h2&gt;Why Use Nebulex in Your Elixir Application?&lt;/h2&gt;
&lt;p&gt;Caching can be implemented in many different ways depending on your application use case. You may need a local cache that stores data directly in your application or a distributed cache. Having a cache framework that supports a vast number of caching solutions is a plus. This is where we can leverage the Nebulex caching toolkit.&lt;/p&gt;
&lt;p&gt;Nebulex has a &lt;em&gt;flexible and pluggable architecture based on adapters&lt;/em&gt;. This makes it possible to integrate different caching options and also provides an easy workaround for various &lt;em&gt;caching topologies&lt;/em&gt;, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Partitioned caching:&lt;/strong&gt; distribution of data between multiple nodes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replicated caching:&lt;/strong&gt; involving multiple servers, where each server has the same copy of data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local caching:&lt;/strong&gt; a single-server cache that resides on a single node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So Nebulex makes it easy for developers to scale their applications beyond a single node (with minimal impact on the code). You only need to choose the adapter that best suits your needs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cabol/nebulex&quot;&gt;Check out this in-depth guide on supported caches and their adapters in Nebulex&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s look at a real-world example where Nebulex proved useful.&lt;/p&gt;
&lt;h2&gt;The Problem: Fetching and Storing Data from an External API&lt;/h2&gt;
&lt;p&gt;A while ago, I was working on a payment integration system that involved fetching a transaction from an external API. The fetched transaction was then stored in the database.&lt;/p&gt;
&lt;p&gt;We also had to confirm if the transaction could complete, so we scheduled a job using &lt;a href=&quot;https://hexdocs.pm/elixir/GenServer.html&quot;&gt;GenServer&lt;/a&gt;. GenServer sent a request to the external API after a certain period of time to confirm if the transaction was complete and then updated the stored transaction status.&lt;/p&gt;
&lt;p&gt;This approach had the following shortcomings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;After every specified period, a request was sent to the external API to confirm if the transaction was completed. This occurred even when all fetched transactions stored in the database were completed.&lt;/li&gt;
&lt;li&gt;After every specified period, a query ran to check if all transactions were complete. This approach resulted in unnecessary trips to the database and was deemed unfit when handling many transactions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Solution: Caching Locally with Nebulex&lt;/h2&gt;
&lt;p&gt;The application was being deployed to a single instance and would frequently access loaded transactions. So to solve the problem stated above, we used Nebulex to locally cache the fetched transactions.&lt;/p&gt;
&lt;p&gt;This approach helped to overcome the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Making unnecessary trips to the external API after every specified period.&lt;/strong&gt; It ensured requests were only made if the cache contained transactions. By default, all cached transactions were incomplete.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Making many trips to the database.&lt;/strong&gt; Trips to the database were made only when inserting a fetched transaction and updating its status.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As mentioned earlier, Nebulex supports different caching solutions, one of which is &lt;em&gt;local caching&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll now implement Nebulex in an Elixir application when caching locally.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s begin!&lt;/p&gt;
&lt;h2&gt;Add Nebulex to an Elixir Application&lt;/h2&gt;
&lt;p&gt;First, open the &lt;code&gt;mix.exs&lt;/code&gt; file and add the &lt;code&gt;nebulex&lt;/code&gt; dependency as shown:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
  {:nebulex, &amp;quot;~&amp;gt; 2.4&amp;quot;}

  ...

  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install the Nebulex dependency:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installation, go ahead and generate your cache:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix nbx.gen.cache -c Payment.Cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This step involves:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defining a cache module within the application&lt;/li&gt;
&lt;li&gt;Setting up configurations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;#39;ll use the name &lt;code&gt;Payment.Cache&lt;/code&gt; to identify our cache (you can name yours as you wish). The command above will generate the &lt;code&gt;Payment.Cache&lt;/code&gt; module defined in &lt;code&gt;lib/payment/cache.ex&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#lib/payment/cache.ex
defmodule Payment.Cache do
  use Nebulex.Cache,
    otp_app: :my_app,
    adapter: Nebulex.Adapters.Local
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command generates the configuration Nebulex will use in &lt;code&gt;config/config.exs&lt;/code&gt;,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#config/config.exs

config :my_app, Payment.Cache,
  # When using :shards as backend
  # backend: :shards,
  # GC interval for pushing new generation: 12 hrs
  gc_interval: :timer.hours(12),
  # Max 1 million entries in cache
  max_size: 1_000_000,
  # Max 2 GB of memory
  allocated_memory: 2_000_000_000,
  # GC min timeout: 10 sec
  gc_cleanup_min_timeout: :timer.seconds(10),
  # GC max timeout: 10 min
  gc_cleanup_max_timeout: :timer.minutes(10)
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Finally, open &lt;code&gt;lib/my_app/application.ex&lt;/code&gt; and add the &lt;code&gt;Payment.Cache&lt;/code&gt; to the application supervision tree.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#lib/my_app/application.ex

use Application

  @impl true
  def start(_type, _args) do
    children = [

      Payment.Cache

      # ...

    ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Setting &lt;code&gt;Payment.Cache&lt;/code&gt; in the supervision tree starts the Nebulex process when the application starts up.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;Nebulex.Cache&lt;/code&gt; Configuration in Elixir&lt;/h2&gt;
&lt;p&gt;The generated &lt;code&gt;Payment.Cache&lt;/code&gt; module uses the &lt;code&gt;Nebulex.Cache&lt;/code&gt;, a cache abstraction layer controlled by adapters. &lt;code&gt;Nebulex.Cache&lt;/code&gt; expects &lt;code&gt;:otp_app&lt;/code&gt; and &lt;code&gt;:adapter&lt;/code&gt; as options.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:otp_app&lt;/code&gt; points to the Elixir application where &lt;code&gt;nebulex&lt;/code&gt; can find the cache configuration. In our case, &lt;code&gt;:my_app&lt;/code&gt; is specified.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:adapter&lt;/code&gt; - the desired adapter is configured at this point. In our case, &lt;code&gt;Nebulex.Adapters.Local&lt;/code&gt; has been specified. It implements a local generation cache. This is a caching technique based on the age of the cached entries. It involves specifying the object&amp;#39;s last modified date in the cache key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The configurations specified in &lt;code&gt;config/config.exs&lt;/code&gt; are specific to &lt;code&gt;Nebulex.Adapters.Local&lt;/code&gt; passed in the &lt;code&gt;:adapter&lt;/code&gt; option.&lt;/p&gt;
&lt;p&gt;These are some of the options supported by &lt;code&gt;Nebulex.Adapters.Local&lt;/code&gt; via the cache configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;:backend&lt;/code&gt;&lt;/strong&gt; - the storage used for the adapter. The supported forms of storage are &lt;code&gt;:ets&lt;/code&gt; and &lt;code&gt;:shards&lt;/code&gt;, and the default is &lt;code&gt;:ets&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;:gc_interval&lt;/code&gt;&lt;/strong&gt; - interval time in milliseconds for garbage collection to run, which involves deleting the oldest generation and creating a new one. Expects an integer &amp;gt; 0.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;:max_size&lt;/code&gt;&lt;/strong&gt; specifies the cache limit. Expects an integer &amp;gt; 0.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;:allocated_memory&lt;/code&gt;&lt;/strong&gt; - maximum size in bytes of the memory allocated for cache generation. Expects an integer &amp;gt; 0.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;:gc_cleanup_min_timeout&lt;/code&gt;&lt;/strong&gt; - minimum timeout in milliseconds for triggering the next clean-up and memory check. Defaults to 10_000 (10 seconds). Expects an integer &amp;gt; 0.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;:gc_cleanup_max_timeout&lt;/code&gt;&lt;/strong&gt; - maximum timeout in milliseconds for triggering the next clean-up and memory check. Defaults to 600_000 (10 minutes). Expects an integer &amp;gt; 0.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/nebulex/Nebulex.Adapters.Local.html#module-options&quot;&gt;Read more about supported module options for &lt;code&gt;Nebulex.Adapters.Local&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Query with &lt;code&gt;Nebulex.Cache&lt;/code&gt; Callbacks&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Nebulex.Cache&lt;/code&gt; module has callbacks that can be leveraged to perform queries. Let&amp;#39;s cache fetched transactions from an external API and manipulate cached entries using callbacks.&lt;/p&gt;
&lt;p&gt;The implementation for manipulating cache entries is in &lt;code&gt;lib/my_app/payment_cache.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#lib/my_app/payment_cache.ex

defmodule MyApp.PaymentCache do
  @moduledoc &amp;quot;&amp;quot;&amp;quot;
  context for manipulating cache entries. It involves;
   - Inserting fetched transaction and incomplete transaction into the cache
   - Query for all cached transaction
   - Deleting cached transaction
  &amp;quot;&amp;quot;&amp;quot;
  alias Payment.Cache

  def insert_transaction(transaction) do
    Cache.put(transaction[&amp;quot;id&amp;quot;], transaction)
  end

  def insert_all_transactions(transactions) do
    transactions
    |&amp;gt; Enum.map(fn transaction -&amp;gt;
      {transaction.id, %{id: transaction.id, status: transaction.status}}
    end)
    |&amp;gt; Cache.put_all()
  end

  def get_transaction(id) do
   Cache.get(id)
  end

  def all_cached_transactions do
    Cache.all()
  end

  def delete_transactions(transaction_ids) when is_list(transaction_ids) do
    unless Enum.empty?(transaction_ids) do
      Enum.each(transaction_ids, fn key -&amp;gt; delete_transaction(id) end)
    end
  end

  def delete_transaction(id) do
    Cache.delete(id)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we create a context for manipulating cache entries related to payments. We alias &lt;code&gt;Payment.Cache&lt;/code&gt; (the module generated above in &lt;code&gt;lib/payment/cache.ex&lt;/code&gt;). The module will give us access to the &lt;code&gt;Nebulex.Cache&lt;/code&gt; callbacks.&lt;/p&gt;
&lt;p&gt;The following functions are defined:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;insert_transaction/1&lt;/code&gt;&lt;/strong&gt; - takes in a fetched transaction from the external API and inserts it into the cache. &lt;a href=&quot;https://hexdocs.pm/nebulex/Nebulex.Cache.html#c:put/3&quot;&gt;Payment.Cache.put/3&lt;/a&gt; is responsible for inserting the transaction into the cache.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;insert_all_transactions/1&lt;/code&gt;&lt;/strong&gt; - takes in a list of transactions and inserts them into the cache by invoking &lt;a href=&quot;https://hexdocs.pm/nebulex/Nebulex.Cache.html#c:put_all/2&quot;&gt;Payment.Cache.put_all/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;all_cached_transactions/0&lt;/code&gt;&lt;/strong&gt; - fetches all cached entries by invoking &lt;a href=&quot;https://hexdocs.pm/nebulex/Nebulex.Cache.html#c:all/2&quot;&gt;Payment.Cache.all/2&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;delete_transaction/1&lt;/code&gt;&lt;/strong&gt; - deletes a cached entry by invoking &lt;a href=&quot;https://hexdocs.pm/nebulex/Nebulex.Cache.html#c:delete/2&quot;&gt;Payment.Cache.delete/2&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;get_transaction/1&lt;/code&gt;&lt;/strong&gt; - fetches a cached transaction from the given key by invoking &lt;a href=&quot;https://hexdocs.pm/nebulex/Nebulex.Cache.html#c:get/2&quot;&gt;Payment.Cache.get/2&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, open an interactive shell in your terminal, and put the functionality into use:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex &amp;gt; alias MyApp.PaymentCache

iex &amp;gt; fetched_transaction = %{id: 1, status: &amp;quot;pending&amp;quot;}

        %{id: 1, status: &amp;quot;pending&amp;quot;}

iex &amp;gt; PaymentCache.insert_transaction(fetched_transaction)

      :ok

iex &amp;gt; PaymentCache.get_transaction(1)

      %{id: 1, status: &amp;quot;pending&amp;quot;}

iex &amp;gt; another_fetched_transaction =  %{id: 2, status: &amp;quot;pending&amp;quot;}

        %{id: 2, status: &amp;quot;pending&amp;quot;}

iex &amp;gt; PaymentCache.insert_transaction(another_fetched_transaction)

      :ok

iex &amp;gt; PaymentCache.all_cached_transactions()
      # returns the ids of the cached transactions
      [1, 2]

iex &amp;gt; PaymentCache.delete_transaction(1)

      :ok


iex &amp;gt; PaymentCache.all_cached_transactions()

      [2]

iex &amp;gt; PaymentCache.get_transaction(1)

      nil
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Schedule a Job in Elixir Using Cached Entries&lt;/h2&gt;
&lt;p&gt;Caching fetched transactions comes in handy when scheduling jobs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#lib/my_app/payment_scheduler.ex

defmodule MyApp.PaymentScheduler do
  use GenServer

  require Logger

  alias MyApp.PaymentCache

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end

  @impl true
  def init(opts) do
    {:ok, opts, {:continue, :cache_incomplete_transactions}}
  end

  @impl true
  def handle_continue(:cache_incomplete_transactions, state) do

    insert_all_transaction()

    schedule_work()


    {:noreply, state}

  end

  @impl true
  def handle_info(:update, state) do
    update_pending_transactions()

    schedule_work()

    {:noreply, state}
  end

  defp schedule_work do
    Process.send_after(self(), :update, 10000)
  end

  defp update_pending_transactions do
    all_cached_transactions = PaymentCache.all_cached_transactions()

    case all_cached_transactions do
      [] -&amp;gt; Logger.info(&amp;quot;All transactions are complete&amp;quot;)

      all_cached_transactions -&amp;gt;

        complete_transactions = complete_transactions(all_cached_transactions)

        Payments.update_incomplete_transactions(complete_transactions)


        # delete cached transactions after update in the db
        PaymentCache.delete_transaction(complete_transactions)
    end
  end

  defp complete_transactions(cached_transactions) do

    #fetch all complete transactions from external API
    complete_transactions = Payment.confirmed_transactions()

    Enum.map(complete_transactions, fn transaction -&amp;gt;
      transaction.id in all_cached_transactions
      transaction.id
    end)

  end

  defp insert_all_transaction do
    pending_transactions = Transactions.all_pending_transactions()

    case Payment.all_pending_transactions() do
      [] -&amp;gt;  Logger.info(&amp;quot;There are no incomplete transactions in the database&amp;quot;)

      pending_transaction -&amp;gt; PaymentCache.insert_all_transaction(pending_transactions)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s run through what&amp;#39;s going on here.&lt;/p&gt;
&lt;p&gt;When an application starts, &lt;code&gt;init/1&lt;/code&gt; will be invoked. Our &lt;code&gt;init/1&lt;/code&gt; returns &lt;code&gt;{:ok, opts, {:continue, :cache all incomplete transactions}}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This will immediately trigger &lt;code&gt;handle_continue(:cache_incomplete_transactions, state)&lt;/code&gt;. Here, all incomplete transactions are fetched from the database and cached. By invoking &lt;code&gt;schedule_work/0&lt;/code&gt;, an updated job is scheduled to take place every 10 seconds.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;handle_continue/2&lt;/code&gt; callback allows us to perform a time-consuming job asynchronously, avoiding race condition cases. For more about &lt;code&gt;handle_continue/2&lt;/code&gt;, I suggest &lt;a href=&quot;https://elixirschool.com/blog/til-genserver-handle-continue/&quot;&gt;Sophie DeBenedetto&amp;#39;s excellent Elixir School article, &amp;#39;TIL GenServer’s handle_continue/2&amp;#39;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;schedule_work/0&lt;/code&gt;, an &lt;code&gt;:update&lt;/code&gt; message notifies the parent process (the GenServer) that there is an update to perform. The &lt;code&gt;:update&lt;/code&gt; message is then handled in the &lt;code&gt;handle_info/2&lt;/code&gt; callback. At this point, we confirm if there are incomplete transactions in the cache (keeping in mind that we only cache incomplete transactions).&lt;/p&gt;
&lt;p&gt;When the cache is empty, that means there are no incomplete transactions. So we skip sending a request to an external API confirming whether the transactions have been completed, and we update their status in the database.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we explored how to use Nebulex for caching data locally in an Elixir application.&lt;/p&gt;
&lt;p&gt;Implementing caching in an Elixir application depends purely on your business use case. When choosing a cache toolkit, make sure it meets your needs.&lt;/p&gt;
&lt;p&gt;Nebulex&amp;#39;s cache toolkit supports a vast number of caching solutions and allows you to implement different topologies with minimal impact on the code.&lt;/p&gt;
&lt;p&gt;Visit &lt;a href=&quot;https://github.com/cabol/nebulex&quot;&gt;Nebulex&amp;#39;s guide&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;p&gt;Happy caching!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Debugging in Elixir and Erlang: An Introduction</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/11/29/debugging-in-elixir-and-erlang-an-introduction.html"/>
    <id>https://blog.appsignal.com/2022/11/29/debugging-in-elixir-and-erlang-an-introduction.html</id>
    <published>2022-11-29T00:00:00+00:00</published>
    <updated>2022-11-29T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first part of a two-part series, we&#039;ll touch on some tools you can use for debugging in Elixir.</summary>
    <content type="html">&lt;p&gt;Welcome to part one of this two-part series on debugging in Elixir and Erlang. In this post, we&amp;#39;ll use several different tools and techniques to debug
Elixir code.&lt;/p&gt;
&lt;p&gt;First, we&amp;#39;ll get to know the demo project I created to
showcase certain tools: &lt;a href=&quot;https://github.com/msramos/dist_messenger&quot;&gt;dist_messenger&lt;/a&gt;. It&amp;#39;s an Elixir
project of a distributed messaging system that can be used directly on &lt;code&gt;IEx&lt;/code&gt;. It
allows users in different nodes to send and receive messages to each other.&lt;/p&gt;
&lt;p&gt;Then, we&amp;#39;ll learn about the basic debugging tools of Elixir: inspect, pry and
dbg.&lt;/p&gt;
&lt;p&gt;In part two, we&amp;#39;ll turn our attention to Erlang, putting together what we learn into a simple script to
trace a process message across nodes.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;The Necessity of Debugging&lt;/h2&gt;
&lt;p&gt;You write a piece of code, you run it, and it doesn&amp;#39;t execute as expected.&lt;/p&gt;
&lt;p&gt;That is what programming looks like most of the time.
Trying to figure out what&amp;#39;s happening can not only be time-consuming, but very
frustrating when we don&amp;#39;t have the right tools.&lt;/p&gt;
&lt;p&gt;Can you level your washing machine without a leveling tool, instead using a ruler?
Of course, but it will take much more time and energy.&lt;/p&gt;
&lt;p&gt;So, to understand what&amp;#39;s happening in our code, it&amp;#39;s good sometimes to take a
few steps back and ask some questions, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is the value of this variable correct?&lt;/li&gt;
&lt;li&gt;Are the transformations being applied to a variable producing the expected
result?&lt;/li&gt;
&lt;li&gt;Are the messages being correctly sent from one process to another?&lt;/li&gt;
&lt;li&gt;Is there any abnormality in resource consumption?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both Elixir and Erlang provide tools to answer these questions. Knowing how
to use the tools certainly adds a lot of value.&lt;/p&gt;
&lt;h2&gt;Getting to Know Our Demo Project&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/msramos/dist_messenger&quot;&gt;dist_messenger&lt;/a&gt; project uses a
combination of &lt;a href=&quot;https://hexdocs.pm/elixir/1.14.1/GenServer.html&quot;&gt;&lt;code&gt;GenServer&lt;/code&gt;&lt;/a&gt;
and &lt;a href=&quot;https://www.erlang.org/doc/man/global.html&quot;&gt;&lt;code&gt;:global&lt;/code&gt;&lt;/a&gt; to provide a
distributed messaging system inside an Erlang cluster.&lt;/p&gt;
&lt;p&gt;Each node in this cluster can handle one user, and its state is maintained by a
single GenServer, the
&lt;a href=&quot;https://github.com/msramos/dist_messenger/blob/main/lib/messenger/messaging_server.ex&quot;&gt;&lt;code&gt;Messenger.MessagingServer&lt;/code&gt;&lt;/a&gt;.
Users can sign in to the cluster with a unique name, which is then registered
across all nodes using the
&lt;a href=&quot;https://www.erlang.org/doc/man/global.html#register_name-2&quot;&gt;&lt;code&gt;:global.register_name/2&lt;/code&gt;&lt;/a&gt;
function.&lt;/p&gt;
&lt;p&gt;For the user interface, the
&lt;a href=&quot;https://github.com/msramos/dist_messenger/blob/main/lib/messenger/iex_client.ex&quot;&gt;&lt;code&gt;Messenger.IExClient&lt;/code&gt;&lt;/a&gt;
provides several functions that allow users to interact with the messaging
system in IEx. This module is imported by the
&lt;a href=&quot;https://github.com/msramos/dist_messenger/blob/main/.iex.exs&quot;&gt;&lt;code&gt;.iex.exs&lt;/code&gt;&lt;/a&gt;
script, so we can use all its functions directly on &lt;code&gt;iex&lt;/code&gt; when running it with
&lt;code&gt;iex -S mix&lt;/code&gt;. &lt;a href=&quot;https://hexdocs.pm/iex/1.14/IEx.html#module-the-iex-exs-file&quot;&gt;Check the docs for &lt;code&gt;.iex.exs&lt;/code&gt;
files&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Because each node handles one user, to get the full experience of this project,
we need to run &lt;a href=&quot;https://www.erlang.org/doc/reference_manual/distributed.html&quot;&gt;multiple
nodes&lt;/a&gt; (by running nodes with a node name and a shared secret cookie). To make
things simple, the project includes a script
&lt;a href=&quot;https://github.com/msramos/dist_messenger/blob/main/start&quot;&gt;&lt;code&gt;start&lt;/code&gt;&lt;/a&gt; that will
do that for us. You just need to give the name (it will run all nodes on
&lt;code&gt;0.0.0.0&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;You&amp;#39;ll notice that the included &lt;code&gt;.iex.exs&lt;/code&gt; script will automatically try to
connect to nodes &lt;code&gt;node0&lt;/code&gt; up to &lt;code&gt;node9&lt;/code&gt; on localhost. So, by
naming the nodes within this range, we should get a cluster.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start two nodes and sign-in two users: user &lt;code&gt;alice&lt;/code&gt; on &lt;code&gt;node0&lt;/code&gt; and &lt;code&gt;bob&lt;/code&gt;
on &lt;code&gt;node1&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# On terminal 1
$ ./start node0

# On terminal 2
$ ./start node0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To sign in to the messaging system, you can call &lt;code&gt;sign in &amp;lt;name&amp;gt;&lt;/code&gt; on iex:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# node0 - user: alice
iex&amp;gt; sign in &amp;quot;alice&amp;quot;
Signed in!
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Now you can send a message to other users using &lt;code&gt;msg &amp;lt;user&amp;gt; &amp;lt;message&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# node0 - user: alice
iex&amp;gt; msg &amp;quot;bob&amp;quot;, &amp;quot;Hello! How are you?&amp;quot;
Message sent!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;bob&lt;/code&gt;&amp;#39;s session, we get a notification that a new message has arrived:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# node1 - user: bob
[!] New message from alice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use the &lt;code&gt;inbox&lt;/code&gt; command to view all received messages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# node1 - user: bob
iex&amp;gt; inbox
&amp;gt; from: alice
&amp;gt; Hello! How are you?
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;alice&lt;/code&gt;&amp;#39;s session, we can use &lt;code&gt;sent&lt;/code&gt; to view all sent messages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# node0 - user: alice
iex&amp;gt; sent
&amp;gt; to: bob
&amp;gt; Hello! How are you?
---
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are also other commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;signout&lt;/code&gt;: signs out the current users from the cluster&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whoami&lt;/code&gt;: prints the current signed-in user&lt;/li&gt;
&lt;li&gt;&lt;code&gt;last_msg&lt;/code&gt;: prints the last received message&lt;/li&gt;
&lt;li&gt;&lt;code&gt;editor&lt;/code&gt;: sends a message like &lt;code&gt;msg&lt;/code&gt;, but it&amp;#39;s interactive&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we know how our example works, let&amp;#39;s get started with debugging!&lt;/p&gt;
&lt;h2&gt;Elixir Debugging Basics&lt;/h2&gt;
&lt;p&gt;You can use the tools in this section to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;quickly gather information about a
specific variable&lt;/li&gt;
&lt;li&gt;get the result of a function call&lt;/li&gt;
&lt;li&gt;check a whole pipe
chain&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They do require changes in the source code, so we&amp;#39;ll use them during
development and tests.&lt;/p&gt;
&lt;h2&gt;Debugging with &lt;code&gt;IO.inspect/2&lt;/code&gt; in Elixir&lt;/h2&gt;
&lt;p&gt;This is the easiest — and probably the first — tool that an Elixir developer will reach for to
investigate issues. The
&lt;a href=&quot;https://hexdocs.pm/elixir/1.14.0/IO.html#inspect/2&quot;&gt;&lt;code&gt;IO.inspect/2&lt;/code&gt;&lt;/a&gt; function
prints the contents of an expression and returns the expression itself.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; name = {:name, &amp;quot;Jack Shephard&amp;quot;}
iex&amp;gt; IO.inspect(name, label: &amp;quot;Name&amp;quot;)
# Name: {:name, &amp;quot;Jack Shephard&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It returns the value of the evaluated expression so that you can use it within a
pipeline. The &lt;code&gt;label&lt;/code&gt; option is very useful when you have multiple calls to
&lt;code&gt;IO.inspect&lt;/code&gt; and need some hints to understand what you are looking at.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;person = %{name: &amp;quot;Kate Austen&amp;quot;}

iex&amp;gt; &amp;quot; some text &amp;quot;
...&amp;gt; |&amp;gt; String.trim()
...&amp;gt; |&amp;gt; String.upcase() |&amp;gt; IO.inspect(label: &amp;quot;Here&amp;quot;)
...&amp;gt; |&amp;gt; String.split()
Here: &amp;quot;SOME TEXT&amp;quot;
[&amp;quot;SOME&amp;quot;, &amp;quot;TEXT&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;IEx.pry&lt;/code&gt; for Elixir&lt;/h2&gt;
&lt;p&gt;While &lt;code&gt;IO.inspect&lt;/code&gt; allows you to read the content of any variable, &lt;code&gt;IEx.pry&lt;/code&gt;
gives us a bit more insight and information on the code.&lt;/p&gt;
&lt;p&gt;You can think of &lt;code&gt;IO.pry&lt;/code&gt; as an interactive &lt;code&gt;IO.inspect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s use it in the &lt;a href=&quot;https://github.com/msramos/dist_messenger/blob/main/lib/messenger/iex_client.ex#L90-L101&quot;&gt;&lt;code&gt;editor/0&lt;/code&gt;
function&lt;/a&gt;
and see what happens:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...

def editor do
  case Messaging.whoami() do
    {:ok, _user} -&amp;gt;
      recipient = IO.gets(&amp;quot;recipient: &amp;quot;) |&amp;gt; String.trim()
      message = IO.gets(&amp;quot;message: &amp;quot;) |&amp;gt; String.trim()

      # Pause the execution here
      require IEx; IEx.pry

      msg(recipient, message)

    _ -&amp;gt;
      IO.puts(&amp;quot;Not signed in!&amp;quot;)
  end
end

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: you &lt;em&gt;must&lt;/em&gt; use IEx in the application context in order to use &lt;code&gt;IEx.pry&lt;/code&gt;.
This means you need to start it with &lt;code&gt;iex -S mix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When you call the &lt;code&gt;editor/0&lt;/code&gt; (after you type in the &lt;em&gt;recipient&lt;/em&gt; and the
&lt;em&gt;message&lt;/em&gt;), the &lt;code&gt;iex&lt;/code&gt; session will pause execution on the line.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; editor
recipient: kate.austen
message: Hello, Kate!
Break reached: Messenger.IExClient.editor/0 (lib/messenger/iex_client.ex:96)

   93:         recipient = IO.gets(&amp;quot;recipient: &amp;quot;) |&amp;gt; String.trim()
   94:         message = IO.gets(&amp;quot;message: &amp;quot;) |&amp;gt; String.trim()
   95:
   96:         require IEx; IEx.pry
   97:
   98:         msg(recipient, message)
   99:

pry&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this new console, you can type a variable&amp;#39;s name to see its
contents:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;pry&amp;gt; recipient
&amp;quot;kate.austen&amp;quot;
pry&amp;gt; message
&amp;quot;Hello, Kate!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Type &lt;code&gt;continue&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt; to continue the execution.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;dbg/2&lt;/code&gt; Debugging in Elixir&lt;/h2&gt;
&lt;p&gt;This is a new feature since Elixir 1.14. It&amp;#39;s pretty much &lt;code&gt;IO.inspect/2&lt;/code&gt; with
superpowers.&lt;/p&gt;
&lt;p&gt;To demonstrate it, we&amp;#39;ll add
&lt;a href=&quot;https://hexdocs.pm/elixir/main/Kernel.html#dbg/2&quot;&gt;&lt;code&gt;dbg&lt;/code&gt;&lt;/a&gt; to &lt;a href=&quot;https://github.com/msramos/dist_messenger/blob/main/lib/messenger/messaging_server.ex#L82&quot;&gt;this
demo line&lt;/a&gt;. It will be called whenever the server receives a message from
another server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# ...

def handle_info({:msg, from, body}, %{inbox: inbox} = state) do
  # ...

  message = {from, body}
  updated_state = %{state | inbox: [message | inbox]} |&amp;gt; dbg()

  {:noreply, updated_state}
end

#...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when your node receives a message, the recipient&amp;#39;s &lt;code&gt;iex&lt;/code&gt; session will
request to pry on the code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[!] New message from jacob
Request to pry #PID&amp;lt;0.159.0&amp;gt; at Messenger.MessagingServer.handle_info/2 (lib/messenger/messaging_server.ex:82)

   79:     end
   80:
   81:     message = {from, body}
   82:     updated_state = %{state | inbox: [message | inbox]} |&amp;gt; dbg()
   83:
   84:     {:noreply, updated_state}
   85:   end

Allow? [Yn]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will open an &lt;code&gt;IEx.pry&lt;/code&gt; session, and you can check the values of all
variables.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;dbg&lt;/code&gt; at the end of a pipe to see what&amp;#39;s happening:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[[&amp;quot;h&amp;quot;], [&amp;quot;i&amp;quot;]] #=&amp;gt; [[&amp;quot;h&amp;quot;], [&amp;quot;i&amp;quot;]
|&amp;gt; List.flatten() #=&amp;gt; [&amp;quot;h&amp;quot;, &amp;quot;i&amp;quot;]
|&amp;gt; Enum.join() #=&amp;gt; &amp;quot;hi
|&amp;gt; dbg()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;dbg/2&lt;/code&gt; is macro-evaluated at compile time. When called, it will inject code
that allows the interpreter to pause an application&amp;#39;s execution and pry the
current context. &lt;a href=&quot;https://blog.appsignal.com/2022/09/13/elixir-1-14-better-debugging-with-dbg-and-more.html&quot;&gt;Check out &amp;#39;Elixir 1.14: Better Debugging with dbg/2 and More&amp;#39;&lt;/a&gt; for an overview of
&lt;code&gt;dbg/2&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Debugging Production Apps with AppSignal&lt;/h2&gt;
&lt;p&gt;After deploying your app to production, AppSignal can help debug issues from the real world.&lt;/p&gt;
&lt;p&gt;Set up &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;AppSignal for your Elixir application&lt;/a&gt;, and you&amp;#39;ll automatically gain access to an error dashboard with information about all the errors in your app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-11/errors-dashboard.png&quot; alt=&quot;Errors dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;From there, you can dig deeper for more information on individual errors, so you can fix them:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-11/specific-error.png&quot; alt=&quot;Specific errors in Elixir&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;Read more about AppSignal for Elixir&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;This post has introduced debugging basics in Elixir using &lt;code&gt;IO.inspect/2&lt;/code&gt;, &lt;code&gt;IEx.pry&lt;/code&gt;, and &lt;code&gt;dbg/2&lt;/code&gt;. Check out &lt;a href=&quot;https://blog.appsignal.com/2021/11/30/three-ways-to-debug-code-in-elixir.html&quot;&gt;Three Ways to Debug Code in Elixir&lt;/a&gt; for some more information.&lt;/p&gt;
&lt;p&gt;Next time, we&amp;#39;ll focus on Erlang specifically, debugging runtime and finding out how to trace an Elixir clustered application using Erlang&amp;#39;s &lt;code&gt;:debugger&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Parser Combinators in Elixir: A Deeper Dive</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/11/15/parser-combinators-in-elixir-a-deeper-dive.html"/>
    <id>https://blog.appsignal.com/2022/11/15/parser-combinators-in-elixir-a-deeper-dive.html</id>
    <published>2022-11-15T00:00:00+00:00</published>
    <updated>2022-11-15T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of our two-part series, we&#039;ll improve the parser combinator we&#039;ve written.</summary>
    <content type="html">&lt;p&gt;In our last post, we wrote a basic parser for phone numbers using Elixir. It was a bit simplistic since it didn&amp;#39;t really respect the format phone numbers are expected to have, but it was a great start.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll now improve the parser to ensure we only accept phone numbers that fit the spec and make our return type an instance of structured data.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive straight in!&lt;/p&gt;
&lt;h2&gt;Formatting Parse Results in Elixir&lt;/h2&gt;
&lt;p&gt;At this point, we&amp;#39;ve got rudimentary parsers processing the main parts of a local phone number. Let&amp;#39;s now make the parse results easier to put into a data structure.&lt;/p&gt;
&lt;p&gt;Right now, our parser output looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt;  Demo.PhoneNumber.Parser.parse(&amp;quot;020-42 84 105&amp;quot;)
{:ok, [&amp;quot;0&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;4&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;8&amp;quot;, &amp;quot;4&amp;quot;, &amp;quot; &amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;5&amp;quot;], &amp;quot;&amp;quot;, %{},
 {1, 0}, 13}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In passing, you might note that the &amp;quot;remaining unparsed&amp;quot; value (third element in the tuple) is the &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; empty string, meaning our parser successfully consumes the entire input string.&lt;/p&gt;
&lt;p&gt;For starters, let&amp;#39;s remove noise from the parse result: we&amp;#39;re not interested in the trunk value (it&amp;#39;s always &lt;code&gt;&amp;quot;0&amp;quot;&lt;/code&gt; and therefore provides no information) or the separator. Nor, for that matter, are we interested in the spaces in the subscriber number. Let&amp;#39;s wrap each of those in an &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#utf8_char/2&quot;&gt;&lt;code&gt;ignore/2&lt;/code&gt;&lt;/a&gt; so they get dropped from the output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  # ...

  area_code =
    ignore(trunk_prefix)
    |&amp;gt; times(digit, 2)

  separator = choice([string(&amp;quot;-&amp;quot;), string(&amp;quot; &amp;quot;)])

  subscriber_number =
    choice([digit, ignore(string(&amp;quot; &amp;quot;))])
    |&amp;gt; times(min: 1)

  dutch_phone_number =
    area_code
    |&amp;gt; concat(ignore(separator))
    |&amp;gt; concat(subscriber_number)
    |&amp;gt; eos()

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This indeed removes the trunk prefix and separator from the parse result (given they&amp;#39;re now both &lt;code&gt;ignore&lt;/code&gt;d), but it isn&amp;#39;t exactly straightforward to understand since all the parts are just dumped into an array:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020-42 84 105&amp;quot;)
{:ok, [&amp;quot;2&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;4&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;8&amp;quot;, &amp;quot;4&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;5&amp;quot;], &amp;quot;&amp;quot;, %{}, {1, 0}, 13}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We should tag the results to identify which ones come from particular parsers. That sounds like a perfect fit for &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#tag/3&quot;&gt;&lt;code&gt;tag/2&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  # ...

  area_code =
    ignore(trunk_prefix)
    |&amp;gt; times(digit, 2)
    |&amp;gt; tag(:area_code)

  # ...

  subscriber_number =
    choice([digit, ignore(string(&amp;quot; &amp;quot;))])
    |&amp;gt; times(min: 1)
    |&amp;gt; tag(:subscriber_number)

  # ...

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;re now closer to our goal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020-42 84 105&amp;quot;)
{:ok,
 [area_code: [&amp;quot;2&amp;quot;, &amp;quot;0&amp;quot;], subscriber_number: [&amp;quot;4&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;8&amp;quot;, &amp;quot;4&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;5&amp;quot;]],
 &amp;quot;&amp;quot;, %{}, {1, 0}, 13}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These values are still a bit messy though: we want a single string value instead of a collection of digit strings. Essentially, we want to &lt;code&gt;Enum.join(digits_strings, &amp;quot;&amp;quot;)&lt;/code&gt;, which is where &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#reduce/3&quot;&gt;&lt;code&gt;reduce/3&lt;/code&gt;&lt;/a&gt; enters the picture:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  # ...

  area_code =
    ignore(trunk_prefix)
    |&amp;gt; times(digit, 2)
    |&amp;gt; reduce({Enum, :join, [&amp;quot;&amp;quot;]})
    |&amp;gt; tag(:area_code)

  # ...

  subscriber_number =
    choice([digit, ignore(string(&amp;quot; &amp;quot;))])
    |&amp;gt; times(min: 1)
    |&amp;gt; reduce({Enum, :join, [&amp;quot;&amp;quot;]})
    |&amp;gt; tag(:subscriber_number)

  # ...

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;re steadily moving towards our goal of having parse results that are nicely formatted and easy to convert into a data structure:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020-42 84 105&amp;quot;)
{:ok, [area_code: [&amp;quot;20&amp;quot;], subscriber_number: [&amp;quot;4284105&amp;quot;]], &amp;quot;&amp;quot;, %{}, {1, 0}, 13}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We still need a little tweak: instead of the tagged values containing an array of a single element, we want to just have the element directly. That&amp;#39;s easy. We&amp;#39;ll just replace our use of &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#tag/3&quot;&gt;&lt;code&gt;tag/3&lt;/code&gt;&lt;/a&gt; with &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#unwrap_and_tag/3&quot;&gt;&lt;code&gt;unwrap_and_tag/3&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  # ...

  area_code =
    ignore(trunk_prefix)
    |&amp;gt; times(digit, 2)
    |&amp;gt; reduce({Enum, :join, [&amp;quot;&amp;quot;]})
    |&amp;gt; unwrap_and_tag(:area_code)

  # ...

  subscriber_number =
    choice([digit, ignore(string(&amp;quot; &amp;quot;))])
    |&amp;gt; times(min: 1)
    |&amp;gt; reduce({Enum, :join, [&amp;quot;&amp;quot;]})
    |&amp;gt; unwrap_and_tag(:subscriber_number)

  # ...

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check it out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020-42 84 105&amp;quot;)
{:ok, [area_code: &amp;quot;20&amp;quot;, subscriber_number: &amp;quot;4284105&amp;quot;], &amp;quot;&amp;quot;, %{}, {1, 0}, 13}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Creating a Struct&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s create a &lt;code&gt;PhoneNumber&lt;/code&gt; struct to hold our parsed data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number.ex

defmodule Demo.PhoneNumber do
  alias Demo.PhoneNumber.Parser

  defstruct [:country_code, :area_code, :subscriber_number]

  def new(string) when is_binary(string) do
    case Parser.parse(string) do
      {:ok, results, &amp;quot;&amp;quot;, _, _, _} -&amp;gt; {:ok, struct!(__MODULE__, results)}
      {:error, reason, _rest, _, _, _} -&amp;gt; {:error, reason}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What do we have here? After defining a struct with &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#defstruct/1&quot;&gt;&lt;code&gt;defstruct/1&lt;/code&gt;&lt;/a&gt;, we define a &lt;code&gt;new/1&lt;/code&gt; function that will accept a string input. Then it will run our fancy parser: if the parser is unable to process the string, it will return &lt;code&gt;{:error, reason}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If, on the other hand, our parser is able to process the string, we know that &lt;code&gt;results&lt;/code&gt; will be a keyword list of the parsed components found in the phone number (such as &lt;code&gt;[area_code: &amp;quot;20&amp;quot;, subscriber_number: &amp;quot;4284105&amp;quot;]&lt;/code&gt; as shown above). And we know this will indeed be a keyword list, because we&amp;#39;ve done so much work getting our parser to format and tag the output in this manner.&lt;/p&gt;
&lt;p&gt;All of this hard work is finally paying off: since our keyword list keys are the same as the struct&amp;#39;s, we can create a new struct instance by simply calling &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#struct!/2&quot;&gt;&lt;code&gt;struct!/2&lt;/code&gt;&lt;/a&gt; with our parse results!&lt;/p&gt;
&lt;p&gt;We now have the public API to parse phone numbers into a data structure. Time for a quick test in &lt;code&gt;iex -S mix&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.new(&amp;quot;020-42 84 105&amp;quot;)
{:ok,
 %Demo.PhoneNumber{
   area_code: &amp;quot;20&amp;quot;,
   country_code: nil,
   subscriber_number: &amp;quot;4284105&amp;quot;
 }}

iex(2)&amp;gt; Demo.PhoneNumber.new(&amp;quot;foobar&amp;quot;)
{:error, &amp;quot;expected ...&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Writing Custom Combinators Using Elixir&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve made great strides so far: our parser now returns a data structure! This will be extremely helpful down the line when the data it contains needs to be validated or otherwise processed.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s still some work ahead of us, though: aside from the fact that it doesn&amp;#39;t yet parse international numbers, it also doesn&amp;#39;t check for number lengths. Area codes may have 2 or 3 digits, while subscriber numbers may have 7 or 6 digits respectively.&lt;/p&gt;
&lt;p&gt;To assist us in achieving this goal, we&amp;#39;ll be writing more advanced and powerful combinators. As you may recall from the &lt;a href=&quot;https://blog.appsignal.com/2022/10/18/parser-combinators-in-elixir-taming-semi-structured-text.html&quot;&gt;previous article&lt;/a&gt;, combinators are parsers that can be combined into bigger and better parsers. We&amp;#39;ll be using NimbleParsec to define a complex parser from smaller and simpler ones.&lt;/p&gt;
&lt;p&gt;Since we want the parser behavior to vary according to provided arguments, we need to define some functions. But since NimbleParsec&amp;#39;s &lt;code&gt;defparsec/3&lt;/code&gt; is executed during compilation, &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#defparsec/3-beware&quot;&gt;we can&amp;#39;t invoke a function defined in the same module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To work around this, we&amp;#39;ll define a &lt;code&gt;Helpers&lt;/code&gt; sub-module and our configurable parsers there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser/helpers.ex

defmodule Demo.PhoneNumber.Parser.Helpers do
  @moduledoc false

  import NimbleParsec

  @doc &amp;quot;&amp;quot;&amp;quot;
  Parses a single digit.
  &amp;quot;&amp;quot;&amp;quot;
  def digit(combinator \\ empty()) do
    combinator
    |&amp;gt; utf8_string([?0..?9], 1)
  end

  @doc &amp;quot;&amp;quot;&amp;quot;
  Parses `count` digits.

  For example, `digits(3)` would parse 3 digits.
  &amp;quot;&amp;quot;&amp;quot;
  def digits(combinator \\ empty(), count) do
    combinator
    |&amp;gt; duplicate(digit(), count)
    |&amp;gt; reduce({Enum, :join, [&amp;quot;&amp;quot;]})
  end

  @doc &amp;quot;&amp;quot;&amp;quot;
  Parses a phone number area code.

  Since phone number area codes can only be 2 or 3 digits in length,
  only `2` and `3` are valid values for the `length` parameter.
  &amp;quot;&amp;quot;&amp;quot;
  def area_code(combinator \\ empty(), length) when length in [2, 3] do
    combinator
    |&amp;gt; digits(length)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we use &lt;code&gt;combinator&lt;/code&gt; as the first function argument, defaulting to NimbleParsec&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#empty/0&quot;&gt;&lt;code&gt;empty()&lt;/code&gt;&lt;/a&gt; combinator if none is provided. This enables us to compose combinators where appropriate, without having to use &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#concat/2&quot;&gt;&lt;code&gt;concat/2&lt;/code&gt;&lt;/a&gt; as a crutch.&lt;/p&gt;
&lt;h3&gt;Updating the Parser with Functions&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s update our parser to use these new functions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec
  import Demo.PhoneNumber.Parser.Helpers

  # ...

  area_code_with_trunk_prefix =
    ignore(trunk_prefix)
    |&amp;gt; area_code(2)
    |&amp;gt; unwrap_and_tag(:area_code)

  # ...

  subscriber_number =
    choice([digit(), ignore(string(&amp;quot; &amp;quot;))])
    |&amp;gt; times(min: 1)
    |&amp;gt; reduce({Enum, :join, [&amp;quot;&amp;quot;]})
    |&amp;gt; unwrap_and_tag(:subscriber_number)

  dutch_phone_number =
    area_code_with_trunk_prefix
    |&amp;gt; concat(ignore(separator))
    |&amp;gt; concat(subscriber_number)
    |&amp;gt; eos()

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ve renamed &lt;code&gt;area_code&lt;/code&gt; to &lt;code&gt;area_code_with_trunk_prefix&lt;/code&gt; so it won&amp;#39;t get confused with the &lt;code&gt;area_code&lt;/code&gt; imported from the new &lt;code&gt;Helpers&lt;/code&gt; module. Also take note that &lt;code&gt;digit&lt;/code&gt; has become &lt;code&gt;digit()&lt;/code&gt;, as it&amp;#39;s now a function rather than a combinator.&lt;/p&gt;
&lt;p&gt;Our code still works, but we&amp;#39;ve yet to fix the subscriber number parser: if the area code is 2 digits, then the subscriber number should be 7 digits. Conversely, if the area code is 3 digits long, the subscriber should contain only 6 digits. So let&amp;#39;s now refactor to have a variable-length &lt;code&gt;subscriber_number&lt;/code&gt; combinator along with a configurable &lt;code&gt;local_number&lt;/code&gt; combinator:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser/helpers.ex

defmodule Demo.PhoneNumber.Parser.Helpers do
  @moduledoc false

  import NimbleParsec

  # ... various combinator definitions ...

  def subscriber_number(combinator \\ empty(), length) when length in [6, 7] do
    combinator
    |&amp;gt; digit()
    |&amp;gt; times(ignore(optional(string(&amp;quot; &amp;quot;))) |&amp;gt; digit(), length - 1)
    |&amp;gt; ignore(optional(string(&amp;quot; &amp;quot;)))
    |&amp;gt; reduce({Enum, :join, [&amp;quot;&amp;quot;]})
  end

  def local_number(combinator \\ empty(), area_code_length, subscriber_number_length) do
    separator = choice([string(&amp;quot;-&amp;quot;), string(&amp;quot; &amp;quot;)])

    combinator
    |&amp;gt; area_code(area_code_length)
    |&amp;gt; unwrap_and_tag(:area_code)
    |&amp;gt; concat(ignore(separator))
    |&amp;gt; concat(subscriber_number(subscriber_number_length) |&amp;gt; unwrap_and_tag(:subscriber_number))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;#39;s quite a bit going on here, so let&amp;#39;s take a look.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Side note&lt;/strong&gt;: if you ever get stuck when writing sub-parsers, you can create entry points to only test that portion of your code. For example, by adding &lt;code&gt;defparsec(:subscriber_number, subscriber_number(7))&lt;/code&gt; at the bottom of &lt;code&gt;Demo.PhoneNumber.Parser&lt;/code&gt;, you can run &lt;code&gt;iex -S mix&lt;/code&gt; and test the parsing of subscriber numbers with &lt;code&gt;Demo.PhoneNumber.Parser.subscriber_number(&amp;quot;65 23 125&amp;quot;)&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The subscriber number is defined as (mandatorily) starting with a digit, followed by an optional space and then another digit, with the latter grouping repeating one time less than the desired length provided as an argument. That means that we&amp;#39;ll end up with as many actual digits as requested via &lt;code&gt;length&lt;/code&gt; (along with a variable number of spaces mixed in). We ignore the whitespace so it won&amp;#39;t show up in the results, and then combine all parsed digits into a single string.&lt;/p&gt;
&lt;p&gt;We then define a &lt;code&gt;local_number&lt;/code&gt; combinator that will accept two lengths: one for the area code, and the other for the subscriber portion. We combine these with an ignored &lt;code&gt;separator&lt;/code&gt;, and tag each segment. Since we know each &lt;code&gt;area_code&lt;/code&gt; and &lt;code&gt;subscriber_number&lt;/code&gt; combinator will yield a single result, we can use &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#unwrap_and_tag/3&quot;&gt;&lt;code&gt;unwrap_and_tag/3&lt;/code&gt;&lt;/a&gt; to extract the parsed result from the returned array and tag it with the provided atom.&lt;/p&gt;
&lt;p&gt;As you may have seen, our &lt;code&gt;subscriber_number&lt;/code&gt; combinator accepts a previous combinator as the first argument: we could have chained it directly to the previous combinator.&lt;/p&gt;
&lt;p&gt;Why, then, are we using &lt;code&gt;concat/2&lt;/code&gt;? Because it will, in effect, &amp;quot;separate&amp;quot; the combinator we&amp;#39;re interested in, so that &lt;code&gt;unwrap_and_tag/3&lt;/code&gt; will apply only to the &lt;code&gt;subscriber_number&lt;/code&gt; sub-parser rather than to the combinator result of &lt;code&gt;subscriber_number&lt;/code&gt; and its prior combinator.&lt;/p&gt;
&lt;p&gt;In addition, the &lt;code&gt;Enum.join&lt;/code&gt; step we have in &lt;code&gt;subscriber_number&lt;/code&gt; would run into problems without &lt;code&gt;concat/2&lt;/code&gt;. It attempts to &lt;code&gt;join&lt;/code&gt; the result of the previous combinator (which will include &lt;code&gt;area_code: &amp;quot;20&amp;quot;&lt;/code&gt;), so it will crash (as &lt;code&gt;Enum.join&lt;/code&gt; won&amp;#39;t know how to process a tuple). Keep this in mind if you run into unexpected failures when writing your own combinators.&lt;/p&gt;
&lt;h2&gt;Rewriting the Main Parser in Elixir&lt;/h2&gt;
&lt;p&gt;With these new custom combinators available, let&amp;#39;s go back and rewrite our main parser:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec
  import Demo.PhoneNumber.Parser.Helpers

  trunk_prefix = string(&amp;quot;0&amp;quot;)

  local_portion =
    choice([
      local_number(2, 7),
      local_number(3, 6)
    ])

  dutch_phone_number =
    ignore(trunk_prefix)
    |&amp;gt; concat(local_portion)
    |&amp;gt; eos()

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nice and readable: we can easily tell that the local portion of the number is always expected to be 9 digits long, with a longer area code resulting in a short subscriber number.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re almost done! We just need to handle the international prefix:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec
  import Demo.PhoneNumber.Parser.Helpers

  # ...

  international_prefix =
    ignore(string(&amp;quot;+&amp;quot;))
    |&amp;gt; digits(2)
    |&amp;gt; ignore(string(&amp;quot; &amp;quot;))
    |&amp;gt; map({String, :to_integer, []})
    |&amp;gt; unwrap_and_tag(:country_code)

  dutch_phone_number =
    choice([international_prefix, ignore(trunk_prefix)])
    |&amp;gt; concat(local_portion)
    |&amp;gt; eos()

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We simply define the &lt;code&gt;international_prefix&lt;/code&gt; combinator using functions that are now familiar to us, and then use &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#map/3&quot;&gt;&lt;code&gt;map/3&lt;/code&gt;&lt;/a&gt; to ensure the result is an integer: we may want to compare it to valid ISO country codes later on.&lt;/p&gt;
&lt;p&gt;With that in place, it&amp;#39;s simply a matter of telling our parser that we&amp;#39;re either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the international case (where our parser does &lt;em&gt;not&lt;/em&gt; expect the trunk prefix to be present)&lt;/li&gt;
&lt;li&gt;In a national context, where the trunk prefix should indeed be part of the phone number (but removed from the output)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voilà, we&amp;#39;ve got our phone number parser defined in a way that&amp;#39;s understandable and easy to maintain. Take a look:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.new(&amp;quot;+31 20-42 84 105&amp;quot;)
{:ok,
 %Demo.PhoneNumber{
   area_code: &amp;quot;20&amp;quot;,
   country_code: 31,
   subscriber_number: &amp;quot;4284105&amp;quot;
 }}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Next Steps: Play Around with Parser Combinators&lt;/h2&gt;
&lt;p&gt;The best way to get a good grasp on how parser combinators work is to experiment with them.&lt;/p&gt;
&lt;p&gt;Want to give it a spin but can&amp;#39;t think of an example? Try extending our code to parse &lt;a href=&quot;https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers#Netherlands&quot;&gt;other cases&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Write a parser for &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601&lt;/a&gt; datetimes such as &lt;code&gt;2019-11-14T00:55:31.820Z&lt;/code&gt;. And if you want to get really crazy, you can extend it to handle &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601#Durations&quot;&gt;durations&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601#Time_intervals&quot;&gt;time intervals&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also try your hand at writing a recursive parser: there&amp;#39;s an &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#parsec/2-examples&quot;&gt;example&lt;/a&gt; in NimbleParsec&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#parsec/2&quot;&gt;&lt;code&gt;parsec/2&lt;/code&gt; documentation&lt;/a&gt; to get you started.&lt;/p&gt;
&lt;p&gt;As touched upon in the introduction to this article, NimbleParsec is more of a parser generator: take a look at &lt;a href=&quot;https://hexdocs.pm/combine/Combine.html&quot;&gt;Combine&lt;/a&gt; and try to convert the above code to make use of Combine, or come up with your own example.&lt;/p&gt;
&lt;p&gt;The way Combine works is that you combine parser functions, and obtain a new parser function. Parser functions can then be applied via &lt;a href=&quot;https://hexdocs.pm/combine/Combine.html#parse/3&quot;&gt;&lt;code&gt;Combine.parse/3&lt;/code&gt;&lt;/a&gt;. Here&amp;#39;s a toy example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# the public parser
def username_and_id(string) do
  Combine.parse(string, username_and_id_parser())
end

# these are internal parsers for the combinator

# a &amp;quot;username and id&amp;quot; is simply a sequence of
# username, space, id
defp username_and_id_parser() do
  sequence([
    username(),
    ignore(string(&amp;quot; &amp;quot;)),
    id()
  ])
end

# a username consists of word characters
defp username(), do: word()

# an id is an integer
defp id(), do: integer()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling this function will return the (non-ignored) parse result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; username_and_id(&amp;quot;foobar 123&amp;quot;)
[[&amp;quot;foobar&amp;quot;, 123]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ready for the big leagues? Write your own parser combinator from scratch to fully understand how everything works under the hood. Here&amp;#39;s &lt;a href=&quot;https://gist.github.com/sasa1977/beaeb43d39b055ecb93b937123b633d5&quot;&gt;an example&lt;/a&gt; parsing a subset of SQL, written by &lt;a href=&quot;https://www.theerlangelist.com/&quot;&gt;Saša Jurić&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In the first part of this series, we briefly defined parser combinators before building a simple one in Elixir.&lt;/p&gt;
&lt;p&gt;In this second and final part, we dived deeper into the parser combinator that we built last time and improved it. We also gave you some ideas for ways to further explore parser combinators.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Sanitize Strings in Elixir with Pattern Matching and Recursion</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/11/01/sanitize-strings-in-elixir-with-pattern-matching-and-recursion.html"/>
    <id>https://blog.appsignal.com/2022/11/01/sanitize-strings-in-elixir-with-pattern-matching-and-recursion.html</id>
    <published>2022-11-01T00:00:00+00:00</published>
    <updated>2022-11-01T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s use two great features in Elixir - recursion and binary pattern matching - to sanitize a string.</summary>
    <content type="html">&lt;p&gt;In this post, we&amp;#39;ll use two of Elixir&amp;#39;s most powerful features - pattern matching and recursion - to sanitize a string by removing invalid Unicode &lt;a href=&quot;https://en.wikipedia.org/wiki/Specials_(Unicode_block)&quot;&gt;&amp;quot;Specials&amp;quot;&lt;/a&gt; characters.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive straight in!&lt;/p&gt;
&lt;h2&gt;The Problem: Strings with Unicode Specials&lt;/h2&gt;
&lt;p&gt;Unicode Specials is a short Unicode block of characters allocated at characters U+FFF0-FFFF. If one of these characters is present in a string of text, that text is &lt;em&gt;not&lt;/em&gt; correctly encoded Unicode text. Here&amp;#39;s the full set of those characters:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0xFFF0
0xFFF1
0xFFF2
0xFFF3
0xFFF4
0xFFF5
0xFFF6
0xFFF7
0xFFF8
0xFFF0
0xFFF10
0xFFF11
0xFFF12
0xFFF13
0xFFF14
0xFFFA
0xFFFB
0xFFFC
0xFFFD
0xFFFE
0xFFFF
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might encounter incorrectly encoded strings that contain a member of the Unicode Specials block. Let&amp;#39;s say you need a way to process those strings anyway. Maybe you have some code that reads file contents or receives string input from another external source, like a form file upload or external API. In this case, you will want to remove these invalid characters to continue processing the text.&lt;/p&gt;
&lt;p&gt;Elixir makes this easy with the help of binary pattern matching and recursion. We&amp;#39;ll build out a function that removes Unicode specials from a string and replaces them with the &lt;code&gt;&amp;quot;�&amp;quot;&lt;/code&gt; replacement character, so your program can continue to process the string input. When we&amp;#39;re done, you&amp;#39;ll have a handy function you can use to sanitize any string and a deeper understanding of two Elixir language features that will prove useful in many other scenarios.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;The Solution: Sanitize Your String with Pattern Matching and Recursion in Elixir&lt;/h2&gt;
&lt;p&gt;Our goal is to produce a function - &lt;code&gt;CleanString.unicode_only/2&lt;/code&gt; - that takes in any string and returns that string, with Unicode Specials replaced with the &lt;code&gt;&amp;quot;�&amp;quot;&lt;/code&gt; replacement character. Here are a few examples of our finished product in action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;CleanString.unicode_only(&amp;quot;abc&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFFFF::16&amp;gt;&amp;gt;)
=&amp;gt; &amp;quot;abc�&amp;quot;
CleanString.unicode_only(&amp;quot;a&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFFFF::16&amp;gt;&amp;gt; &amp;lt;&amp;gt; &amp;quot;bc&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFFFF::16&amp;gt;&amp;gt;)
=&amp;gt; &amp;quot;a�bc�&amp;quot;
CleanString.unicode_only(&amp;quot;abc&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFFF2::16&amp;gt;&amp;gt; &amp;lt;&amp;gt; &amp;quot;def&amp;quot;)
=&amp;gt; &amp;quot;abc�def&amp;quot;
CleanString.unicode_only(&amp;lt;&amp;lt;0xFFF5::16&amp;gt;&amp;gt; &amp;lt;&amp;gt; &amp;quot;def&amp;quot;)
=&amp;gt; &amp;quot;�def&amp;quot;
CleanString.unicode_only(&amp;lt;&amp;lt;0xFFF5::16&amp;gt;&amp;gt; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFFF4::16&amp;gt;&amp;gt; &amp;lt;&amp;gt; &amp;quot;def&amp;quot;)
=&amp;gt; &amp;quot;��def&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 1: Break Down the Problem&lt;/h3&gt;
&lt;p&gt;Before we write any code, let&amp;#39;s break down this problem one step at a time:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For each character in a string&lt;/li&gt;
&lt;li&gt;Check if that character is present in the &lt;code&gt;@specials&lt;/code&gt; list&lt;/li&gt;
&lt;li&gt;If it is, remove it from the string&lt;/li&gt;
&lt;li&gt;And replace it with the replacement character&lt;/li&gt;
&lt;li&gt;If it is not present in the &lt;code&gt;@specials&lt;/code&gt; list&lt;/li&gt;
&lt;li&gt;Keep that character&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Changing elements in place in a string is a tricky and potentially expensive operation, but Elixir gives us another way.&lt;/p&gt;
&lt;p&gt;We can use binary pattern matching to iterate over each element in our string, recursively breaking off the &amp;quot;head&amp;quot; or first character of the string. Then, depending on whether or not that character is considered valid, we will add it to the head of a &lt;em&gt;new&lt;/em&gt; string.&lt;/p&gt;
&lt;p&gt;Pulling the head off a string and adding to the head of a new string are very performant tasks in Elixir--it doesn&amp;#39;t matter how long the string is, Elixir will only ever need to remove from or add to the beginning of that string.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s break down our problem one more time, this time with our new strategy in place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For each character in a string&lt;/li&gt;
&lt;li&gt;Check if that character is present in the &lt;code&gt;@specials&lt;/code&gt; list&lt;/li&gt;
&lt;li&gt;If it is, add a replacement character to the head of a &lt;em&gt;new string&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;If it is not, add that character to the head of a &lt;em&gt;new string&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This will result in a brand new string that contains only replacement or valid Unicode characters.&lt;/p&gt;
&lt;p&gt;With our plan in place, we&amp;#39;re ready to write some code.&lt;/p&gt;
&lt;h3&gt;Step 2: Define the Module in Elixir&lt;/h3&gt;
&lt;p&gt;First up, we&amp;#39;ll define a module, &lt;code&gt;CleanString&lt;/code&gt;, that sets a module attribute, &lt;code&gt;@specials&lt;/code&gt;, to a list of binary strings that represent the characters in the specials block listed above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CleanString do
    @specials [
    &amp;lt;&amp;lt;255, 240&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 241&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 242&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 243&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 244&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 245&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 246&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 247&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 248&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 240&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 16&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 17&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 18&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 19&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 20&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 250&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 251&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 252&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 253&amp;gt;&amp;gt;
    &amp;lt;&amp;lt;255, 254&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 255&amp;gt;&amp;gt;
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;This list of binary strings is generated by taking each specials character and evaluating its hexadecimal bitstring version like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; &amp;lt;&amp;lt;0xFFFF::16&amp;gt;&amp;gt;
&amp;lt;&amp;lt;255, 255&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want our module to store this list of binary strings so that we can check each character of the given string against this list and remove it if it&amp;#39;s found.&lt;/p&gt;
&lt;p&gt;Now that we have the basics of our module in place, let&amp;#39;s start building the &lt;code&gt;unicode_only/2&lt;/code&gt; function.&lt;/p&gt;
&lt;h3&gt;Step 3: Define the &lt;code&gt;unicode_only/2&lt;/code&gt; Function in Elixir&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;unicode_only/2&lt;/code&gt; function will take in two arguments: the original string and the new &amp;quot;clean&amp;quot; string we&amp;#39;re building.&lt;/p&gt;
&lt;p&gt;We plan to call our function recursively. The &lt;em&gt;first&lt;/em&gt; time, we call it with only one argument--the argument of the original string--like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;CleanString.unicode_only(&amp;quot;abc&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFFFF::16&amp;gt;&amp;gt;)
=&amp;gt; &amp;quot;abc�&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this scenario, we need to default the &amp;quot;clean string&amp;quot; second argument to an empty string. Let&amp;#39;s define that default argument function head first:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CleanString do

  @specials [
    # ...
  ]

  def unicode_only(string, new_string \\ &amp;quot;&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great, now we&amp;#39;re ready to define the remainder of our function heads. Here&amp;#39;s where Elixir&amp;#39;s powerful binary pattern matching feature comes in.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll define one version of the function that pattern matches a scenario where the character at the head of the string is included in the &lt;code&gt;@specials&lt;/code&gt; list, and one in which it isn&amp;#39;t. Let&amp;#39;s start with that first scenario:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@replacement_character &amp;quot;�&amp;quot;

def unicode_only(&amp;lt;&amp;lt;head::binary-size(2)&amp;gt;&amp;gt; &amp;lt;&amp;gt; tail, new_string)
    when head in @specials do
  unicode_only(tail, @replacement_character &amp;lt;&amp;gt; new_string)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we&amp;#39;ve added a new module attribute, &lt;code&gt;@replacement_character&lt;/code&gt;, that stores our replacement character. Then, we&amp;#39;ve added a version of the &lt;code&gt;unicode_only/2&lt;/code&gt; function that uses binary pattern matching to extract the first two bytes of the string and set them equal to a variable, &lt;code&gt;head&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why do we need to capture the first two bytes of the string to check if the first character is part of the Unicode Specials block? This is because each individual specials character is represented by a two-byte binary string.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a closer look at how we capture those two bytes now. The magic happens in the first argument given to &lt;code&gt;unicode_only/2&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;&amp;lt;head::binary-size(2)&amp;gt;&amp;gt; &amp;lt;&amp;gt; tail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Elixir allows you to pattern match &lt;em&gt;in the function head&lt;/em&gt;. This means that when &lt;code&gt;unicode_only/2&lt;/code&gt; is called, the first argument given will be pattern matched against this definition. For example, if we call the function like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;original_string = &amp;quot;abc&amp;quot; &amp;lt;&amp;gt; &amp;lt;&amp;lt;0xFFFF::16&amp;gt;&amp;gt;
CleanString.unicode_only(original_string)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the following pattern match will be executed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;&amp;lt;head::binary-size(2)&amp;gt;&amp;gt; &amp;lt;&amp;gt; tail = original_string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As mentioned above, this results in setting the variable &lt;code&gt;head&lt;/code&gt; equal to the first two bytes of the string. Meanwhile, the &lt;code&gt;tail&lt;/code&gt; variable is bound to the remainder of the string. Then, we use a guard clause to check if that variable is included in the &lt;code&gt;@specials&lt;/code&gt; list.&lt;/p&gt;
&lt;p&gt;If it is, we don&amp;#39;t want to add it to the new clean string we&amp;#39;re constructing. Instead, we want to add the replacement character:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@replacement_character &amp;lt;&amp;gt; new_string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to perform this same operation for the &lt;em&gt;next&lt;/em&gt; character in the original string, and the next one, and so on. This is where recursion comes in. We will call &lt;code&gt;unicode_only/2&lt;/code&gt; &lt;em&gt;again&lt;/em&gt;. This time with only the &lt;code&gt;tail&lt;/code&gt; of the original string as a first argument, and the newly constructed clean string as a second argument:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;unicode_only(tail, @replacement_character &amp;lt;&amp;gt; new_string)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this way, we recursively pull the head off the string, until the string is empty. Now, we have a function head that runs when the first two bytes of the string &lt;em&gt;are&lt;/em&gt; included in &lt;code&gt;@specials&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s define another version of our function that will run when the first character &lt;em&gt;isn&amp;#39;t&lt;/em&gt; included there.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt; def unicode_only(&amp;lt;&amp;lt;head::binary-size(1)&amp;gt;&amp;gt; &amp;lt;&amp;gt; tail, new_string) do
  new_string = head &amp;lt;&amp;gt; new_string
  unicode_only(tail, new_string)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once again, we use binary pattern matching in the function head. This time, we pattern match the first argument given to &lt;code&gt;unicode_only/2&lt;/code&gt; against the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;&amp;lt;head::binary-size(1)&amp;gt;&amp;gt; &amp;lt;&amp;gt; tail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we pull off the &lt;em&gt;first byte&lt;/em&gt; of the string and set it equal to the &lt;code&gt;head&lt;/code&gt; variable, and we set the remainder of the string equal to &lt;code&gt;tail&lt;/code&gt;. We only want to grab the first byte of the string here because non-specials characters are represented by a single byte, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; &amp;lt;&amp;lt;99&amp;gt;&amp;gt;
&amp;quot;c&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Moving our attention back to the function body, let&amp;#39;s talk about how this function behaves. In the scenario where the first character is not included in &lt;code&gt;@specials&lt;/code&gt; we &lt;em&gt;do&lt;/em&gt; want to retain that character in our new string. So we add it to the head of the new string, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;head &amp;lt;&amp;gt; new_string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we&amp;#39;re ready to recursively call our function again, with the remaining &lt;code&gt;tail&lt;/code&gt; of the original string and our updated new string:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;unicode_only(tail, head &amp;lt;&amp;gt; new_string)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;re almost done. We just need a way to break out of our recursive loop when the time is right. When do we want to stop recursing? When we&amp;#39;ve processed every character in the original string. When this happens, the original string will be empty, and the first argument passed to &lt;code&gt;unicode_only/2&lt;/code&gt; in our recursive loop will be &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;. Let&amp;#39;s implement that function head now, once again using pattern matching:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def unicode_only(&amp;quot;&amp;quot;, new_string), do: String.reverse(new_string)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the original string is finally empty, we &lt;em&gt;don&amp;#39;t&lt;/em&gt; want to call &lt;code&gt;unicode_only/2&lt;/code&gt; again. Instead, we&amp;#39;ll return the reversed new string.&lt;/p&gt;
&lt;p&gt;We need to reverse the string because we added each processed character to the &lt;em&gt;head&lt;/em&gt; of the new string to keep our code performant. So, we added each retained or replacement character in the opposite order from their placement in the original string. Reversing the string when we&amp;#39;re done puts everything back in the right order.&lt;/p&gt;
&lt;p&gt;Putting it all together, we end up with this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CleanString do

  @specials [
    &amp;lt;&amp;lt;255, 240&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 241&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 242&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 243&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 244&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 245&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 246&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 247&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 248&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 240&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 16&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 17&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 18&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 19&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 20&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 250&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 251&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 252&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 254&amp;gt;&amp;gt;,
    &amp;lt;&amp;lt;255, 255&amp;gt;&amp;gt;
  ]

  @replacement_character &amp;quot;�&amp;quot;

  def unicode_only(string, new_string \\ &amp;quot;&amp;quot;)

  def unicode_only(&amp;lt;&amp;lt;head::binary-size(2)&amp;gt;&amp;gt; &amp;lt;&amp;gt; tail, new_string)
      when head in @specials do
    unicode_only(tail, @replacement_character &amp;lt;&amp;gt; new_string)
  end

  def unicode_only(&amp;lt;&amp;lt;head::binary-size(1)&amp;gt;&amp;gt; &amp;lt;&amp;gt; tail, new_string) do
    unicode_only(tail, head &amp;lt;&amp;gt; new_string)
  end

  def unicode_only(&amp;quot;&amp;quot;, new_string), do: String.reverse(new_string)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;With a set of functions implemented in around ten lines of code, we&amp;#39;ve created an elegant solution for a common, tough problem. Thanks to Elixir&amp;#39;s powerful pattern matching functionality, which we used here to pattern match binary strings &lt;em&gt;in&lt;/em&gt; function heads, we have a handy function for cleaning bad characters out of any string.&lt;/p&gt;
&lt;p&gt;String sanitization is something that you may need to do in the wild, and Elixir is a perfect fit for the job.
Beyond that specific scenario though, this solution demonstrates how nicely Elixir pattern matching and recursion go hand in hand.&lt;/p&gt;
&lt;p&gt;Instead of implementing complex and difficult-to-read &lt;code&gt;if&lt;/code&gt; statements, our recursive code flow was built entirely with pattern matching. Each scenario was mapped to a different &lt;code&gt;unicode_only/2&lt;/code&gt; function head.&lt;/p&gt;
&lt;p&gt;Reach for function head pattern matching whenever you want to execute different function behavior based on different inputs, and you&amp;#39;ll end up with clean, highly readable, and maintainable code. You can even pattern match on single characters, or groups of characters, in a binary string with the syntax you&amp;#39;ve seen here.&lt;/p&gt;
&lt;p&gt;Taken together, pattern matching and recursion are a match made in Elixir heaven. Add these tools to your Elixir toolbox and take them out whenever you have a complex input processing problem to solve.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Parser Combinators in Elixir: Taming Semi-Structured Text</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/10/18/parser-combinators-in-elixir-taming-semi-structured-text.html"/>
    <id>https://blog.appsignal.com/2022/10/18/parser-combinators-in-elixir-taming-semi-structured-text.html</id>
    <published>2022-10-18T00:00:00+00:00</published>
    <updated>2022-10-18T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first of a two-part series, we&#039;ll explore how parser combinators work in Elixir.</summary>
    <content type="html">&lt;p&gt;The need to manipulate strings comes up quite often, whether it&amp;#39;s to validate user-provided values or transform text into structured data that can be used programmatically.&lt;/p&gt;
&lt;p&gt;Most often, we&amp;#39;ll reach for regular expressions to accomplish this task, but sometimes there&amp;#39;s a better solution to the problem: parser combinators. In this two-part article, we&amp;#39;ll explore how they work.&lt;/p&gt;
&lt;p&gt;Before moving on, let&amp;#39;s define what &amp;#39;parsing&amp;#39; is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;parser&lt;/strong&gt; is a software component that takes input data (frequently text) and builds a data structure.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://en.wikipedia.org/wiki/Parsing#Parser&quot;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In other words, when talking about transforming text into structured data, we essentially mean parsing.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get into it!&lt;/p&gt;
&lt;h2&gt;Parser Combinators: The What, How, and Why&lt;/h2&gt;
&lt;p&gt;So what are parser combinators? Well, as their name implies, they are parsers that can be combined — to make bigger, better parsers.&lt;/p&gt;
&lt;p&gt;In effect, parser combinators enable the writing of complex parsers from simpler ones. You&amp;#39;re less likely to make mistakes, and the parsers are a lot easier to maintain due to better readability.&lt;/p&gt;
&lt;p&gt;In contrast, regular expressions are often a poor choice for non-trivial parsing. Writing them is error-prone, they&amp;#39;re challenging to maintain, and their format doesn&amp;#39;t lend itself well to documentation/explanation.&lt;/p&gt;
&lt;p&gt;To illustrate working with parser combinators, we&amp;#39;ll work on transforming a string representation of a Dutch phone number into a canonical representation. This can prove useful, as a web form can capture a user&amp;#39;s phone number to later be used programmatically, for example.&lt;/p&gt;
&lt;h2&gt;The &amp;quot;Parser&amp;quot; and &amp;quot;Combinator&amp;quot; Bits: NimbleParsec&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll be using &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html&quot;&gt;NimbleParsec&lt;/a&gt; as the resulting parsers are more efficient, but other libraries such as &lt;a href=&quot;https://hexdocs.pm/combine/api-reference.html&quot;&gt;Combine&lt;/a&gt; also exist and work well.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;As an aside, note that it&amp;#39;s been pointed out that &lt;a href=&quot;https://twitter.com/sasajuric/status/1183505479709933568&quot;&gt;NimbleParsec is more akin to a parser generator&lt;/a&gt; than a parser combinator: that&amp;#39;s true, but the difference won&amp;#39;t matter when learning how to make use of parser generators.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Parser Examples in Elixir&lt;/h3&gt;
&lt;p&gt;As mentioned before, parsing is the act of taking unstructured data (typically strings) and transforming them into structured data.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ve got some examples right in Elixir.&lt;/p&gt;
&lt;p&gt;We can turn a string containing a URI into a data structure via &lt;a href=&quot;https://hexdocs.pm/elixir/URI.html#new/1&quot;&gt;&lt;code&gt;URI.new/1&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; URI.new(&amp;quot;https://elixir-lang.org/&amp;quot;)
{:ok, %URI{
  fragment: nil,
  host: &amp;quot;elixir-lang.org&amp;quot;,
  path: &amp;quot;/&amp;quot;,
  port: 443,
  query: nil,
  scheme: &amp;quot;https&amp;quot;,
  userinfo: nil
}}

iex&amp;gt; URI.new(&amp;quot;/invalid_greater_than_in_path/&amp;gt;&amp;quot;)
{:error, &amp;quot;&amp;gt;&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, we can convert a string representation of an integer into an actual integer by using &lt;a href=&quot;https://hexdocs.pm/elixir/Integer.html#parse/2&quot;&gt;&lt;code&gt;Integer.parse/2&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Integer.parse(&amp;quot;34&amp;quot;)
{34, &amp;quot;&amp;quot;}

iex&amp;gt; Integer.parse(&amp;quot;34.5&amp;quot;)
{34, &amp;quot;.5&amp;quot;}

iex&amp;gt; Integer.parse(&amp;quot;three&amp;quot;)
:error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of these examples will accept a string and either return a parsed result (possibly with &amp;quot;leftover&amp;quot; string content, as in the &lt;code&gt;Integer.parse/2&lt;/code&gt; example) or an error indication.&lt;/p&gt;
&lt;h3&gt;Combinator Examples in Elixir&lt;/h3&gt;
&lt;p&gt;What if we had lists indicating how many visitors came from URIs (formatted as &amp;quot;URI &amp;amp; count&amp;quot; pairs)? It would be nice to have a single function to do the heavy lifting for us:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; parse_visit_count(&amp;quot;https://elixir-lang.org/ 123&amp;quot;)
{:ok, %{
  referrer: %URI{
    fragment: nil,
    host: &amp;quot;elixir-lang.org&amp;quot;,
    path: &amp;quot;/&amp;quot;,
    port: 443,
    query: nil,
    scheme: &amp;quot;https&amp;quot;,
    userinfo: nil
  },
  visits: 123
}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Easy, I hear you say — just do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def parse_visit_count(string) do
  with [uri_string, count_string | []] &amp;lt;- string |&amp;gt; String.trim() |&amp;gt; String.split(),
        {:ok, uri} &amp;lt;- URI.new(uri_string),
        {count, &amp;quot;&amp;quot;} &amp;lt;- Integer.parse(count_string) do
    {:ok, %{referrer: uri, visits: count}}
  else
    _ -&amp;gt; :error
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s indeed pretty straightforward. But what if there are several URI/visits pairs per line? Then the logic is already much more involved. And what if these URI/visits pairs are in reverse order (visits first, then URI)?&lt;/p&gt;
&lt;p&gt;Using a parser combinator approach, we look at the problem differently. We&amp;#39;ve got a parser for URIs, and another one for integers. Let&amp;#39;s write a parser for white space, then combine those three parsers into a single one for our specific use case. In pseudo-code, it would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def parse_visit_count(...) do
   ...
   |&amp;gt; uri_parser()
   |&amp;gt; whitespace_parser()
   |&amp;gt; integer_parser()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And since we&amp;#39;re now in combinator-land, we could then use &lt;code&gt;parse_visit_count&lt;/code&gt; and combine it with other parsers to step up the complexity. Neat, right?&lt;/p&gt;
&lt;h2&gt;Code Walkthrough: Our Parser Combinator Example&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s work through a concrete example of using a parser combinator: we&amp;#39;ll parse a phone number into a data structure.&lt;/p&gt;
&lt;p&gt;The phone number we&amp;#39;ll use for our examples is one from the Netherlands: +31 20 42 84 105.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers#Netherlands&quot;&gt;Wikipedia&lt;/a&gt;, this number can be formatted in various ways (note we&amp;#39;ll only be covering a subset of the possibilities within this article):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The area code (&amp;#39;A&amp;#39;) is commonly separated with a dash (&amp;#39;-&amp;#39;) and sometimes a space from the subscriber&amp;#39;s number (&amp;#39;B&amp;#39;).
The length of the area code for landlines is either 2 or 3 digits, depending on the population density of the area. This leaves 7 or 6 digits for the subscriber&amp;#39;s number, resulting in a format of either &lt;em&gt;0AA-BBBBBBB&lt;/em&gt; or &lt;em&gt;0AAA-BBBBBB&lt;/em&gt;. [...]
The trunk prefix &amp;#39;0&amp;#39; is dropped when prefixed by the country code: +31 AA BBBBBBBB, [...], etcetera. [...]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, this phone number can also be formatted as (among others):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;+31 20 4284105&lt;/li&gt;
&lt;li&gt;+31 20-42 84 105&lt;/li&gt;
&lt;li&gt;020-42 84 105&lt;/li&gt;
&lt;li&gt;020-4284105&lt;/li&gt;
&lt;li&gt;020 42 84 105&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Deconstructing the Problem&lt;/h3&gt;
&lt;p&gt;From a quick look at the formats above, we can tell that the main &amp;quot;chunks&amp;quot; we need to extract are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Country code - the &amp;quot;+31&amp;quot; prefix, which may be absent&lt;/li&gt;
&lt;li&gt;Area code - the &amp;quot;020&amp;quot;, &amp;quot;(0)20&amp;quot;, or &amp;quot;20&amp;quot; value&lt;/li&gt;
&lt;li&gt;Subscriber number - the remaining seven digits, which may be separated by spaces&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Getting Started&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll use &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html&quot;&gt;NimbleParsec&lt;/a&gt;, so let&amp;#39;s go ahead and create a new project with &lt;code&gt;mix new demo&lt;/code&gt; and add the dependency in &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# in mix.exs

defp deps do
  [
    {:nimble_parsec, &amp;quot;~&amp;gt; 1.2&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run &lt;code&gt;mix deps.get&lt;/code&gt; to ensure everything&amp;#39;s ready for us. With that in place, let&amp;#39;s start writing our phone number parser, which we&amp;#39;ll do within its own module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  dutch_phone_number = string(&amp;quot;+31 20 42 84 105&amp;quot;)

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within this &lt;code&gt;PhoneNumber.Parser&lt;/code&gt; module, we need to &lt;code&gt;import NimbleParsec&lt;/code&gt; so we can call on its functions (such as &lt;code&gt;string&lt;/code&gt;) more conveniently. Then, we define our parser. Right now, that consists of only parsing the exact phone number string via NimbleParsec&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#string/2&quot;&gt;&lt;code&gt;string/2&lt;/code&gt;&lt;/a&gt; function (hence why the phone number value is hardcoded). And last but not least, we call &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#defparsec/3&quot;&gt;&lt;code&gt;defparsec/3&lt;/code&gt;&lt;/a&gt; to &amp;quot;finalize&amp;quot; the parser and make it executable.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s give it a spin! Open an IEx session by typing &lt;code&gt;iex -S mix&lt;/code&gt; in the project&amp;#39;s root folder from within a terminal. We can then try our parser:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;+31 20 42 84 105&amp;quot;)
{:ok, [&amp;quot;+31 20 42 84 105&amp;quot;], &amp;quot;&amp;quot;, %{}, {1, 0}, 16}

iex(2)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;foobar&amp;quot;)
{:error, &amp;quot;expected string \&amp;quot;+31 20 42 84 105\&amp;quot;&amp;quot;, &amp;quot;foobar&amp;quot;, %{}, {1, 0}, 0}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result is a tuple containing six terms. The first is the &lt;code&gt;:ok&lt;/code&gt; or &lt;code&gt;:error&lt;/code&gt; tag indicating whether the provided string could be parsed.&lt;/p&gt;
&lt;p&gt;The second value is (in the &lt;code&gt;:ok&lt;/code&gt; case) a list of the parsed information, or (in the &lt;code&gt;:error&lt;/code&gt; case) the error reason.&lt;/p&gt;
&lt;p&gt;The remaining values can be ignored as we won&amp;#39;t get into them in this article.&lt;/p&gt;
&lt;h3&gt;Parsing Local Numbers&lt;/h3&gt;
&lt;p&gt;Now that we&amp;#39;ve created a parser for an exact string, let&amp;#39;s dig deeper into NimbleParsec&amp;#39;s functionality by expanding the variety of phone numbers our parser will be able to process.&lt;/p&gt;
&lt;p&gt;Local phone numbers look like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;020-42 84 105&lt;/li&gt;
&lt;li&gt;020-4284105&lt;/li&gt;
&lt;li&gt;020 42 84 105&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;#39;s an area code, then a separator which can be a space or a dash. This is followed by the subscriber number, which can contain spaces to make it easier to read.&lt;/p&gt;
&lt;p&gt;Note also that the &amp;quot;area code&amp;quot; portion consists of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Trunk_prefix&quot;&gt;trunk prefix&lt;/a&gt; (which is &amp;quot;0&amp;quot;) followed by two or three numbers indicating the area itself.&lt;/p&gt;
&lt;p&gt;So conceptually, we&amp;#39;re looking at writing a parser that looks like &lt;code&gt;area_code &amp;lt;&amp;gt; separator &amp;lt;&amp;gt; subscriber_number&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start with the area code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  trunk_prefix = string(&amp;quot;0&amp;quot;)

  area_code =
    trunk_prefix
    |&amp;gt; string(&amp;quot;20&amp;quot;)

  dutch_phone_number = area_code

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s give it a whirl in &lt;code&gt;iex -S mix&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020-42 84 105&amp;quot;)
{:ok, [&amp;quot;0&amp;quot;, &amp;quot;20&amp;quot;], &amp;quot;-42 84 105&amp;quot;, %{}, {1, 0}, 3}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see our parser is properly extracting out the area code: it&amp;#39;s being returned as &lt;code&gt;[&amp;quot;0&amp;quot;, &amp;quot;20&amp;quot;]&lt;/code&gt; because the &lt;code&gt;area_code&lt;/code&gt; combinator is composed of &lt;code&gt;trunk_prefix&lt;/code&gt; (yielding &amp;quot;0&amp;quot;), followed by &lt;code&gt;string(&amp;quot;20&amp;quot;)&lt;/code&gt; (logically yielding &amp;quot;20&amp;quot;). The remainder of the input string is left unparsed (as &lt;code&gt;&amp;quot;-42 84 105&amp;quot;&lt;/code&gt;). Success!&lt;/p&gt;
&lt;p&gt;So what&amp;#39;s going on? We create a &lt;code&gt;trunk_prefix&lt;/code&gt; parser that will match the specific &amp;quot;0&amp;quot; string by using &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#string/2&quot;&gt;&lt;code&gt;string/2&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then, we define an &lt;code&gt;area_code&lt;/code&gt; parser that matches this &lt;code&gt;trunk_prefix&lt;/code&gt; followed by the &amp;quot;20&amp;quot; string. And finally, we define the &lt;code&gt;parse&lt;/code&gt; function as the parser specified by the &lt;code&gt;area_code&lt;/code&gt; combinator by calling &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#defparsec/3&quot;&gt;&lt;code&gt;defparsec/3&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re on a roll, so let&amp;#39;s add to our current parser so that it also captures the separator. This separator can be either a dash or a space. It sounds like a perfect match for &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#choice/3&quot;&gt;&lt;code&gt;choice/3&lt;/code&gt;&lt;/a&gt;, which will apply the first parser it finds that can parse the input.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  # ...

  separator = choice([string(&amp;quot;-&amp;quot;), string(&amp;quot; &amp;quot;)])

  dutch_phone_number =
    area_code
    |&amp;gt; concat(separator)

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;choice([string(&amp;quot;-&amp;quot;), string(&amp;quot; &amp;quot;)])&lt;/code&gt;, the &lt;code&gt;choice([...])&lt;/code&gt; combinator will attempt to parse a &lt;code&gt;&amp;quot;-&amp;quot;&lt;/code&gt; string. If it&amp;#39;s not able to, it will attempt parsing a &lt;code&gt;&amp;quot; &amp;quot;&lt;/code&gt; string. Only if both of these options fail, does the entire &lt;code&gt;choice&lt;/code&gt; combinator fail. Conversely, if the first &lt;code&gt;string(&amp;quot;-&amp;quot;)&lt;/code&gt; option succeeds, none of the subsequent parsers provided to &lt;code&gt;choice&lt;/code&gt; will be tested.&lt;/p&gt;
&lt;p&gt;You&amp;#39;ll notice that we weren&amp;#39;t able to simply pipe the two &lt;code&gt;area_code&lt;/code&gt; and &lt;code&gt;separator&lt;/code&gt; combinators into each other: &lt;code&gt;separator&lt;/code&gt; doesn&amp;#39;t accept an argument, so we can&amp;#39;t pass in &lt;code&gt;area_code&lt;/code&gt;. NimbleParsec does, however, make it easy to concatenate two combinators with &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#concat/2&quot;&gt;&lt;code&gt;concat/2&lt;/code&gt;&lt;/a&gt;, so that&amp;#39;s exactly how we plug these two functions into one another. Let&amp;#39;s check things still work as expected:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# in `iex -S mix`

iex(1)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020-42 84 105&amp;quot;)
{:ok, [&amp;quot;0&amp;quot;, &amp;quot;20&amp;quot;, &amp;quot;-&amp;quot;], &amp;quot;42 84 105&amp;quot;, %{}, {1, 0}, 4}

iex(2)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020 42 84 105&amp;quot;)
{:ok, [&amp;quot;0&amp;quot;, &amp;quot;20&amp;quot;, &amp;quot; &amp;quot;], &amp;quot;42 84 105&amp;quot;, %{}, {1, 0}, 4}

iex(3)&amp;gt; Demo.PhoneNumber.Parser.parse(&amp;quot;020/42 84 105&amp;quot;)
{:error, &amp;quot;expected string \&amp;quot;-\&amp;quot; or string \&amp;quot; \&amp;quot;&amp;quot;, &amp;quot;/42 84 105&amp;quot;, %{}, {1, 0}, 3}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great! Both the dash and space separators are getting picked up, while the invalid slash yields an error.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s now write an overly accepting parser that we can come back to and tighten down: we want to capture all digit and space characters until &amp;quot;end of string&amp;quot;. To do so, we&amp;#39;ll use &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#utf8_string/3&quot;&gt;&lt;code&gt;utf8_string/3&lt;/code&gt;&lt;/a&gt; to parse digits, &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#times/3&quot;&gt;&lt;code&gt;times/3&lt;/code&gt;&lt;/a&gt; to get us repetition, and finally, &lt;a href=&quot;https://hexdocs.pm/nimble_parsec/NimbleParsec.html#eos/1&quot;&gt;&lt;code&gt;eos/1&lt;/code&gt;&lt;/a&gt; to represent &amp;quot;end of string&amp;quot;. It looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/demo/phone_number/parser.ex

defmodule Demo.PhoneNumber.Parser do
  @moduledoc false

  import NimbleParsec

  # ...

  digit = utf8_string([?0..?9], 1)

  area_code =
    trunk_prefix
    |&amp;gt; times(digit, 2)

  # ...

  subscriber_number =
    choice([digit, string(&amp;quot; &amp;quot;)])
    |&amp;gt; times(min: 1)

  dutch_phone_number =
    area_code
    |&amp;gt; concat(separator)
    |&amp;gt; concat(subscriber_number)
    |&amp;gt; eos()

  defparsec(:parse, dutch_phone_number)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We define our &lt;code&gt;digit&lt;/code&gt; combinator as a UTF8 string that contains values in the 0-9 range and is of length 1: in other words, it&amp;#39;s a string of a single digit.&lt;/p&gt;
&lt;p&gt;Note we&amp;#39;ve also improved the &lt;code&gt;area_code&lt;/code&gt; combinator: instead of matching only the specific &amp;quot;20&amp;quot; area code, it will match any two digits. The side effect is that the parse results will be slightly different: &lt;code&gt;[&amp;quot;0&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;0&amp;quot;, &amp;quot;-&amp;quot;, ...]&lt;/code&gt; instead of &lt;code&gt;[&amp;quot;0&amp;quot;, &amp;quot;20&amp;quot;, &amp;quot;-&amp;quot;, ...]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Finally, since &lt;code&gt;eos()&lt;/code&gt; has an optional combinator argument, there&amp;#39;s no need to wrap it with a &lt;code&gt;concat()&lt;/code&gt; call within the pipeline.&lt;/p&gt;
&lt;h2&gt;Time for a Short Intermission&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve covered a decent amount of ground so far. Let&amp;#39;s take a break and let all of that sink in.&lt;/p&gt;
&lt;p&gt;Our parser is starting to take shape, but it&amp;#39;s still not very good. We&amp;#39;ll improve it in the next installment where we&amp;#39;ll investigate writing custom parsers, among other topics.&lt;/p&gt;
&lt;p&gt;Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Phoenix LiveView 0.18: New Special HTML Attributes</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/10/11/phoenix-liveview-018-new-special-html-attributes.html"/>
    <id>https://blog.appsignal.com/2022/10/11/phoenix-liveview-018-new-special-html-attributes.html</id>
    <published>2022-10-11T00:00:00+00:00</published>
    <updated>2022-10-11T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s check out Phoenix LiveView 0.18&#039;s new special HTML attributes to help you write cleaner HTML.</summary>
    <content type="html">&lt;p&gt;Phoenix LiveView 0.18 just shipped, with lots of new goodies to make developing LiveView an even better experience.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;#39;ll take you through a lesser-known new feature - LiveView&amp;#39;s new special HTML attributes - and show you how to write cleaner HTML with &lt;code&gt;:if&lt;/code&gt;, &lt;code&gt;:for&lt;/code&gt;, and &lt;code&gt;:let&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When we&amp;#39;re done, you&amp;#39;ll have an eloquent, ergonomic, and dynamic function component you can use to render a list anywhere in your LiveView app.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;What are Special HTML Attributes in LiveView 0.18?&lt;/h2&gt;
&lt;p&gt;LiveView special HTML attributes are inspired by a Surface feature called &lt;a href=&quot;https://surface-ui.org/template_syntax#directives&quot;&gt;&amp;quot;directives&amp;quot;&lt;/a&gt;. Directives are built-in attributes that modify the translated code of a tag or component at compile time.&lt;/p&gt;
&lt;p&gt;Directives are just one of a few new features, like component &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#module-slots&quot;&gt;slots&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#module-attributes&quot;&gt;declarative assigns&lt;/a&gt;, that LiveView has drawn from Surface. Surface is LiveView&amp;#39;s independently developed, open-source component library, and it has often driven LiveView framework development forward by introducing (and battle-testing) new concepts quickly.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;:if&lt;/code&gt; and &lt;code&gt;:for&lt;/code&gt; special attributes provide syntactic sugar for the &lt;code&gt;&amp;lt;%= if ... do %&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;%= for ... do %&amp;gt;&lt;/code&gt; EEx calls you would normally expect to write in your templates.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;:let&lt;/code&gt; attribute works a little bit differently. It is used in component slots when you want to yield a variable from within the function component back up to the caller. You&amp;#39;ll see this most often when you use the &lt;code&gt;.form/1&lt;/code&gt; function component, but you can also use it to make your own function components even more dynamic.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at how you can use these attributes to write eloquent, ergonomic HTML in your LiveView templates. Along the way, you&amp;#39;ll combine the usage of all three of these attributes to build a clean and dynamic LiveView function component.&lt;/p&gt;
&lt;h2&gt;Cleaner LiveView Templates with &lt;code&gt;:if&lt;/code&gt; and &lt;code&gt;:for&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;You can use these two attributes in regular Phoenix templates, in components, and in slots to write cleaner HTML code. We&amp;#39;ll take a look at an example using the &lt;code&gt;:if&lt;/code&gt; directive first:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;div class=&amp;quot;alert alert-danger&amp;quot; :if={@error_message}&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= @error_message %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The div with the &lt;code&gt;alert alert-danger&lt;/code&gt; class that contains the error message markup will only render &lt;em&gt;if&lt;/em&gt; the &lt;code&gt;@error_message&lt;/code&gt; is present and evaluates to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This approach replaces the more verbose one here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;%= if @error_message do %&amp;gt;
&amp;lt;div class=&amp;quot;alert alert-danger&amp;quot;&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= @error_message %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code that uses the &lt;code&gt;:if&lt;/code&gt; attribute is easier to read--more eloquent--and easier to write--more ergonomic.&lt;/p&gt;
&lt;p&gt;You can also use the &lt;code&gt;:if&lt;/code&gt; attribute to conditionally render a function component, all in one simple line of code. Let&amp;#39;s say we have a function component, &lt;code&gt;.error/1&lt;/code&gt;, that wraps up the error message markup above. We can conditionally render it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;.error message={@error_message} :if={@error_message}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&amp;#39;s take a look at an example that uses the &lt;code&gt;:for&lt;/code&gt; attribute. The &lt;code&gt;:for&lt;/code&gt; attribute can be used to iteratively render some content for each member in a collection, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;tbody id=&amp;quot;books&amp;quot;&amp;gt;
  &amp;lt;tr :for={book &amp;lt;- @books}&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;%= book.title %&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Thanks to the &lt;code&gt;:for&lt;/code&gt; attribute, you don&amp;#39;t have to establish your &lt;code&gt;for&lt;/code&gt; loop explicitly within EEx tags, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;tbody id=&amp;quot;books&amp;quot;&amp;gt;
  &amp;lt;%= for book &amp;lt;- @books %&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;%= book.title %&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;/tr&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/tbody&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once again, we&amp;#39;re left with code that is both more eloquent and more ergonomic. You can even combine the usage of &lt;code&gt;:if&lt;/code&gt; and &lt;code&gt;:for&lt;/code&gt; if you need to. Let&amp;#39;s say we have a list of books to render, but we only want to display a given book if it is available in our online store. We can achieve that like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;ul&amp;gt;
  &amp;lt;li :for={book &amp;lt;- @books} :if={book.available}&amp;gt;&amp;lt;%= book.title %&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since both &lt;code&gt;:if&lt;/code&gt; and &lt;code&gt;:for&lt;/code&gt; can be used in either plain HTML or in LiveView function components, we can wrap our list item HTML markup in a function component. Given the following function component:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def list_item(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;li&amp;gt;
    &amp;lt;%= @book.title %&amp;gt;
  &amp;lt;/li&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can call on it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erb&quot;&gt;&amp;lt;ul&amp;gt;
  &amp;lt;.list_item :for={book &amp;lt;- @books} :if={book.available} /&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a nice way to start compartmentalizing our markup into reusable function components made even cleaner with special HTML attributes.&lt;/p&gt;
&lt;p&gt;We can do better with our function component, though. Right now, we&amp;#39;ve only encapsulated the markup for list items, not the entire list. On top of that, our &lt;code&gt;.list_item/1&lt;/code&gt; function component isn&amp;#39;t very reusable--it expects to be called with an assigns that contains an &lt;code&gt;@book&lt;/code&gt; attribute set to something that responds to &lt;code&gt;.title&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll build a more dynamic function component that uses component slots and the &lt;code&gt;:let&lt;/code&gt; attribute to encapsulate the &lt;em&gt;entire&lt;/em&gt; unordered list into one dynamic component. When we&amp;#39;re done, you&amp;#39;ll have a dynamic function component that uses &lt;code&gt;:for&lt;/code&gt; and &lt;code&gt;:let&lt;/code&gt; to render any collection, anywhere in your LiveView app.&lt;/p&gt;
&lt;p&gt;For this next example, we&amp;#39;ll simplify our logic a bit by dropping the &lt;code&gt;:if&lt;/code&gt; attribute and the requirement that a book should only render if it&amp;#39;s available. We&amp;#39;ll just focus on using &lt;code&gt;:let&lt;/code&gt; and &lt;code&gt;:for&lt;/code&gt;. Let&amp;#39;s get started.&lt;/p&gt;
&lt;h2&gt;Dynamic Function Components with &lt;code&gt;:let&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;First up, let&amp;#39;s use a named component slot to create a function component that renders an unordered list and its list items. Start by defining a top-level &lt;code&gt;.unordered_list/1&lt;/code&gt; function component that renders a named slot, &lt;code&gt;:list_item&lt;/code&gt;, inside the appropriate markup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def unordered_list(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;
      &amp;lt;%= render_slot(@list_item, ...) %&amp;gt;
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;re on track to render our unordered list component like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;.unordered_list&amp;gt;
  # ...
&amp;lt;/unordered_list&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we call on the component, we&amp;#39;ll set an assigns - &lt;code&gt;items&lt;/code&gt; - equal to the list of books. Now, we can use &lt;code&gt;:for&lt;/code&gt; in the function component HEEx to render a list item slot for each item in the &lt;code&gt;@items&lt;/code&gt; assigns:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def unordered_list(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;ul :for={item &amp;lt;- @items}&amp;gt;
    &amp;lt;li&amp;gt;
      &amp;lt;%= render_slot(@list_item, item) %&amp;gt;
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting it all together, we can call on our function component like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;.unordered_list items={@books}&amp;gt;
  &amp;lt;:list_item :let={book}&amp;gt;
    &amp;lt;%= book.title&amp;gt;
  &amp;lt;/:list_item&amp;gt;
&amp;lt;/.unordered_list&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s where the &lt;code&gt;:let&lt;/code&gt; special attribute comes in. In our function component, we are using &lt;code&gt;:for&lt;/code&gt; to iterate over the list of books in the &lt;code&gt;@items&lt;/code&gt; assignment. For each book in the list, bound to the &lt;code&gt;item&lt;/code&gt; variable at each step in the iteration, we are calling &lt;code&gt;render_slot/2&lt;/code&gt; with a second argument of &lt;code&gt;item&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The call to &lt;code&gt;:let={book}&lt;/code&gt; when we call on our &lt;code&gt;:list_item&lt;/code&gt; slot sets a variable - &lt;code&gt;book&lt;/code&gt; - equal to the second argument passed into &lt;code&gt;render_slot/2&lt;/code&gt;. In this way, you yield variables from your function components back to the caller with the &lt;code&gt;:let&lt;/code&gt; attribute. So, where we call &lt;code&gt;:list_item&lt;/code&gt; when rendering the function component, we can operate on the &lt;code&gt;book&lt;/code&gt; variable to display its title.&lt;/p&gt;
&lt;p&gt;By combining &lt;code&gt;:for&lt;/code&gt; and &lt;code&gt;:let&lt;/code&gt;, we end up with an eloquent, ergonomic, and highly dynamic function component that we can use again and again in our application to render any collection into an unordered list.&lt;/p&gt;
&lt;p&gt;Before we wrap up, there&amp;#39;s one limitation that I&amp;#39;d like to point out here. Bringing back our &amp;quot;only render a book title if the book is available&amp;quot; logic is a little tricky here. You might want to do something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;.unordered_list items={@books}&amp;gt;
  &amp;lt;:list_item :let={book} :if={book.available}&amp;gt;
    &amp;lt;%= book.title&amp;gt;
  &amp;lt;/:list_item&amp;gt;
&amp;lt;/.unordered_list&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not possible, however. The component slot call cannot combine &lt;code&gt;:let&lt;/code&gt; with &lt;code&gt;:if&lt;/code&gt; in that manner. We can&amp;#39;t take advantage of the &lt;code&gt;:if&lt;/code&gt; attribute here and instead have to write something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def unordered_list(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;ul :for={item &amp;lt;- @items}&amp;gt;
    &amp;lt;%= if item.available %&amp;gt;
      &amp;lt;li&amp;gt;
        &amp;lt;%= render_slot(@list_item, item) %&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The downside is that the component becomes aware of the need to call &lt;code&gt;.available&lt;/code&gt; on the item, making it less reusable.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;LiveView is being adopted so quickly in the Elixir community (and beyond) partly because of its gentle learning curve and emphasis on developer happiness.&lt;/p&gt;
&lt;p&gt;LiveView&amp;#39;s new special HTML attributes make writing LiveView templates even easier and more fun. By borrowing ergonomic features from Surface, we end up with code that is painless to write (fewer onerous EEx tags!) and easy to understand and maintain.&lt;/p&gt;
&lt;p&gt;Reach for these special HTML attributes when writing plain HEEx templates, LiveView HEEx templates, or function components. You&amp;#39;ll end up with beautiful code.&lt;/p&gt;
&lt;p&gt;Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Faster XML Parsing with Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/10/04/faster-xml-parsing-with-elixir.html"/>
    <id>https://blog.appsignal.com/2022/10/04/faster-xml-parsing-with-elixir.html</id>
    <published>2022-10-04T00:00:00+00:00</published>
    <updated>2022-10-04T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Explore how you can parse XML effectively with Elixir using a few different methods.</summary>
    <content type="html">&lt;p&gt;The XML data format has been around since 1996. It was first envisioned as a lingua franca (bridging language)
for data to be serialized and read into completely disparate systems (with
different programming languages, operating systems, and even hardware). It has
been wildly successful in that goal.&lt;/p&gt;
&lt;p&gt;In software, though, 26 years is like a lifetime — and in hardware, it&amp;#39;s an eternity. So much has
changed in that short time that it&amp;#39;s easy to forget just how different the world was when
the standard was proposed.&lt;/p&gt;
&lt;p&gt;That brings us to the topic of today&amp;#39;s post. How can we parse XML quickly and efficiently? What does state-of-the-art XML parsing look like?&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;XML Parsing with Elixir — An Introduction&lt;/h2&gt;
&lt;p&gt;As much as we may want to criticize XML (and there is plenty to
criticize), we have to put it in its historical context. Anything that survives that
long has clearly found some utility!&lt;/p&gt;
&lt;p&gt;Thinking critically about XML as a format is great if you are in a position to change
or improve it, or when deciding whether you should use it.&lt;/p&gt;
&lt;p&gt;But for most, the
choice is already made for us. The entire airline industry and much of finance run on XML — so if
you work in those industries, you will likely need to parse it.&lt;/p&gt;
&lt;p&gt;We will define parsing in this post as doing two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Verifying a document is valid (i.e., that it is actually XML).&lt;/li&gt;
&lt;li&gt;Extracting values from that valid document.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A valid document is not much use if we can&amp;#39;t access the values in our
program&amp;#39;s XML. We will also specifically talk about XML documents where we know the expected shape of the XML ahead of time.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll provide an overview of some possibilities when parsing XML, including actual numbers from
real-world applications.&lt;/p&gt;
&lt;h2&gt;Three Approaches to XML Parsing with Elixir&lt;/h2&gt;
&lt;p&gt;There are three broad approaches we will talk about:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Building a DOM&lt;/li&gt;
&lt;li&gt;Virtual Token Descriptor (VTD)&lt;/li&gt;
&lt;li&gt;Simple API for XML (SAX) parsing&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Building a DOM&lt;/h3&gt;
&lt;p&gt;Building a DOM from XML is probably the most common way to think about XML
parsing. It&amp;#39;s what browsers do with HTML, and it preserves the tree structure that can make
thinking about and validating an XML document much easier.&lt;/p&gt;
&lt;p&gt;DOM stands for Document Object Model — but it really means a structured representation of XML in your given language. Elixir doesn&amp;#39;t have Objects, but we can still have a DOM.&lt;/p&gt;
&lt;p&gt;There are lots of mature tools in this area. Erlang even comes with a built-in data
structure for representing an XML document called &lt;a href=&quot;https://www.erlang.org/doc/man/xmerl.html&quot;&gt;xmerl&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Xmerl represents XML so that &lt;a href=&quot;https://www.w3schools.com/xml/xpath_intro.asp&quot;&gt;XPath&lt;/a&gt;
queries are possible, and an XPath query engine is also built into Erlang. What is XPath?
It is to XML what SQL is to a database — a query language for accessing the data inside it.&lt;/p&gt;
&lt;p&gt;For example, here is an XPath query to get the text from the XML snippet below: &lt;code&gt;/Author/text()&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Author&amp;gt;James Eagan&amp;lt;/Author&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use built-in functions to access the text in the tags:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;xml = &amp;quot;&amp;lt;Author&amp;gt;James Eagan&amp;lt;/Author&amp;gt;&amp;quot;
# First build the xmerl:
{xmerl, _} = xml |&amp;gt; :erlang.binary_to_list |&amp;gt; :xmerl_scan.string()

# Now we can apply the xpath.
:xmerl_xpath.string(&amp;#39;/Author/text()&amp;#39;, xmerl)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tooling maturity can be a fast way to get up and running. There is a chance
your team knows of XPath from other languages, which makes extracting data a breeze,
and using the built-in xmerl format means 0 extra dependencies.&lt;/p&gt;
&lt;p&gt;But there is a problem. Resources! With large XML files creating an xmerl, DOM
can really balloon memory requirements. It can become prohibitively expensive in
terms of latency and memory. Here is a Benchee output excerpt of a ~9mb XML file
that uses xmerl and XPath:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;Benchmarking xmerl with querying ...

Name                                   ips        average  deviation         median         99th %
...
xmerl with querying                 0.0809        12.36 s     ±1.98%        12.42 s        12.59 s

Comparison:
...
xmerl with querying                 0.0809 - 12.68x slower +11.39 s

Memory usage statistics:

Name                            Memory usage
...
xmerl with querying               2340.31 MB - 10.22x memory usage +2111.41 MB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s a lot of megabytes! And as the output indicates, we can do much better.&lt;/p&gt;
&lt;h2&gt;Virtual Token Descriptor (VTD) in Elixir&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://vtd-xml.sourceforge.io/&quot;&gt;VTD&lt;/a&gt; stands for Virtual Token Descriptor. A VTD is a
completely different way to think about parsing XML. Instead of building a DOM, the idea is
to tokenize the XML document and store the locations of key bits of information
inside it.&lt;/p&gt;
&lt;p&gt;In Elixir, this could mean storing the start index and length of all the nodes and attrs
in the XML. You then use &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Kernel.html#binary_part/3&quot;&gt;binary_part&lt;/a&gt;
to access any given location (in constant time!) and extract values when needed.&lt;/p&gt;
&lt;p&gt;We leave the original XML binary untouched in a VTD approach (unlike a DOM, where we manipulate the original XML binary). Instead, in a VTD we build up all the information we need to query the original binary.&lt;/p&gt;
&lt;h3&gt;VTD to XML Parsing: An Example&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s imagine a simplified example. This is not how VTD works exactly, but it will give
you a sense of what it does without getting bogged down in edge cases.&lt;/p&gt;
&lt;p&gt;Given this XML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Author age=&amp;quot;22&amp;quot;&amp;gt;Seth Milchick&amp;lt;/Author&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s imagine the information we want to be able to retrieve is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node name — &lt;code&gt;&amp;quot;Author&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;age attribute — &lt;code&gt;&amp;quot;22&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Author&amp;gt;&lt;/code&gt;&amp;#39;s text content&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To do that, we could build a table that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;xml = &amp;quot;&amp;lt;Author age=\&amp;quot;22\&amp;quot;&amp;gt;Seth Milchick&amp;lt;/Author&amp;gt;&amp;quot;

table = [
  {:node, 1, 5},
  {:attribute, 8, 3},
  {:attribute_value, 13, 2},
  {:text, 17, 13},
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tuple denotes what we are pointing at, e.g., &lt;code&gt;:node&lt;/code&gt;, then provides the
start index for that element. The last number in the tuple is how long the element is.&lt;/p&gt;
&lt;p&gt;If we look to get the XPath &lt;code&gt;/Author/text()&lt;/code&gt;, we can access that table
and see if the root node matches &lt;code&gt;&amp;quot;Author&amp;quot;&lt;/code&gt;, something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;node_in_table? = Enum.any?(table, fn
  {:node, start, length} -&amp;gt; binary_part(xml, start, length) == &amp;quot;Author&amp;quot;
  _ -&amp;gt; false
end)

if node_in_table? do
  case Enum.find(table, &amp;amp;match?({:attribute_value, _, _}, &amp;amp;1)) do
    nil -&amp;gt; :not_text
    {:attribute_value, start, length} -&amp;gt; binary_part(xml, start, length)
  end
else
  :not_found
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, how we represent that table is very important. This is the secret sauce
of VTD. If we were inefficient, we could end up with a table the same size (or
larger!) than a DOM. Or we could take a long time to find the element we
care about in the table, eliminating any potential performance gains from &lt;code&gt;binary_part&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An actual VTD table stores references to child and sibling nodes in a way that makes
randomly accessing a given element as good as in a DOM. However, because we don&amp;#39;t chop up the
original binary into its own objects, the memory requirements can be vastly lower. The creators claim that the table&amp;#39;s size can only be 1.5 times the size of the
XML document. Lower memory requirements also mean it can be &lt;em&gt;fast&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In fact, the parsing method was designed for on-chip implementations.
&lt;a href=&quot;http://www.ximpleware.com/wp_SUN.pdf&quot;&gt;This &amp;#39;XML on a Chip?&amp;#39; document&lt;/a&gt; describes how you can use custom
hardware to blaze through XML!&lt;/p&gt;
&lt;p&gt;What&amp;#39;s more, existing VTD implementations all support the full XPath feature set.
That means it is (in theory) possible to have custom hardware churn through XML parsing
without incurring a massive cost in developer complexity. I say &amp;#39;in theory&amp;#39; because you first have to create the custom hardware, and then
execute it with a suitably low-level language.&lt;/p&gt;
&lt;p&gt;In fact, there are currently no Elixir libraries for VTD. I know of two libraries
being worked on (one in Erlang and one in Elixir) as part-time open source
projects, as of yet unfinished and unreleased. Perhaps you can take inspiration
from &lt;a href=&quot;https://github.com/dryade/vtd-xml&quot;&gt;other languages&lt;/a&gt; and have a go at porting it.&lt;/p&gt;
&lt;p&gt;As cool and interesting as this approach sounds, though, there are more trade-offs.&lt;/p&gt;
&lt;h3&gt;Trade-offs of VTD&lt;/h3&gt;
&lt;p&gt;While XPath is probably familiar to some, it...isn&amp;#39;t great. When a node in a path doesn&amp;#39;t
exist, you just get &lt;code&gt;nil&lt;/code&gt; or an empty string back. This is a pain because you are never
sure if you mistyped the path or if the value actually isn&amp;#39;t there. Verifying that can
be manual and annoying. XPath functions also don&amp;#39;t tell you which node doesn&amp;#39;t exist, making
debugging harder. Having XPath as the primary way you extract data from an XML document
can prove quite painful.&lt;/p&gt;
&lt;p&gt;Additionally, VTD requires an entire document to exist in memory first, unlike sax parsing (as we
will see). This could make parsing a stream of XML with VTD difficult.&lt;/p&gt;
&lt;p&gt;Finally, there is a minimum amount of data that we need to extract from an XML document.
We need to turn that data into useful things (like an Elixir &lt;code&gt;Date&lt;/code&gt; struct) and those Elixir data
structures are of a certain size. If they amount to more in memory than the parsing takes,
we don&amp;#39;t gain anything from further reducing the memory footprint of the parsing. In some situations,
the impressive memory savings don&amp;#39;t translate to an actual saving in our programs (because as soon as you transform the parsed data into structured data, the memory jumps up again anyway).&lt;/p&gt;
&lt;p&gt;So, let&amp;#39;s look at our final approach — sax parsing.&lt;/p&gt;
&lt;h2&gt;SAX Parsing in Elixir&lt;/h2&gt;
&lt;p&gt;A SAX (Simple API for XML) parser works by iterating through a document and emitting
events when certain things happen. For example, the &lt;a href=&quot;https://github.com/qcam/saxy&quot;&gt;Saxy&lt;/a&gt;
parser emits the following events.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;:start_document
:start_element
:characters
:cdata
:end_element
:end_document
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When Saxy sees the start of a tag, for example, it gets its name and attributes and calls a callback you can implement. You can do
whatever you like with that information.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The specific events available vary by implementation. Erlang has a built-in
&lt;a href=&quot;https://www.erlang.org/doc/man/xmerl_xsd.html&quot;&gt;SAX xmerl parser&lt;/a&gt; that offers extra events
like &lt;code&gt;:comment&lt;/code&gt; and &lt;code&gt;:ignorableWhitespace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The emission of events is usually very fast. In Elixir, we can use binary pattern matching
to great effect; Saxy will iterate through a document and use pattern matching to extract
node names and attributes. But this only achieves half of what you actually need.
You then have to identify when a value is one you care about, which is
not as simple as it sounds.&lt;/p&gt;
&lt;h3&gt;SAX Parsing: An Example&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s imagine you want to access the text inside the &lt;code&gt;&amp;lt;Name&amp;gt;&lt;/code&gt; tag below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Author&amp;gt;
  &amp;lt;Name&amp;gt;Nick Riviera&amp;lt;/Name&amp;gt;
&amp;lt;/Author&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this simple case, you first need to wait for the &lt;code&gt;:start_element&lt;/code&gt; event where the &lt;code&gt;node_name&lt;/code&gt;
is &lt;code&gt;Name&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(:start_element, {&amp;quot;Name&amp;quot;, attrs}, state) do
  # In here we know we have just opened the Name tag.
end

# This case is for any other tag that we open.
def handle_event(:start_element, {_, _attrs}, state) do
 {:ok, state}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the &lt;code&gt;:characters&lt;/code&gt; event is separate, meaning we have to put something into the
state to let us know which tag&amp;#39;s characters we&amp;#39;re seeing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(:start_element, {&amp;quot;Name&amp;quot;, attrs}, state) do
  # In here we know we have just opened the Name tag, so let&amp;#39;s just put that in state.
  {:ok, [{&amp;quot;Name&amp;quot;, attrs} | state]}
end

def handle_event(:start_element, {_, _attrs}, state) do
 {:ok, state}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when we get the &lt;code&gt;:characters&lt;/code&gt; event, we can check the state and see if we are &amp;quot;inside&amp;quot;
the tag we care about:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# If &amp;quot;state&amp;quot; is the name tag we know it&amp;#39;s the text we care about.
def handle_event(:characters, text, [{&amp;quot;Name&amp;quot;, _} | rest]) do
  # Now we can do something with the text since we know it will be the text of &amp;lt;Name&amp;gt;.
  # ...
end

def handle_event(:characters, _, state) do
 {:ok, state}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That works great, but now consider this XML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Blog&amp;gt;
  &amp;lt;Name&amp;gt;XML Parsing&amp;lt;/Name&amp;gt;
  &amp;lt;Author&amp;gt;
    &amp;lt;Name&amp;gt;Nick Riviera&amp;lt;/Name&amp;gt;
  &amp;lt;/Author&amp;gt;
&amp;lt;/Blog&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our approach will break here because we need to know &lt;em&gt;which&lt;/em&gt; &lt;code&gt;&amp;lt;Name&amp;gt;&lt;/code&gt; node we have encountered.&lt;/p&gt;
&lt;p&gt;The solution is to use a stack. Each time we open a tag, we add that element to the
stack, and when we close an element, we can discard it.&lt;/p&gt;
&lt;h3&gt;Trade-offs of a Stack&lt;/h3&gt;
&lt;p&gt;Changing our mindset to think
in stacks is not simple, especially when we normally think in recursion.&lt;/p&gt;
&lt;p&gt;It also makes validating the XML more complicated. If you don&amp;#39;t get the value that you expect,
it can be difficult to figure out what went wrong and when. You can print the stack, but figuring
out how it got to be like that basically requires implementing your own stack
tracing algorithm. So debugging is not trivial.&lt;/p&gt;
&lt;p&gt;Implementing the callbacks for each XML document you want to parse can be
an awful lot of work. It is difficult to re-use shared code across handlers because
each time you accumulate different state. You might want to create an &lt;code&gt;%Author{}&lt;/code&gt; struct for this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Author&amp;gt;
  &amp;lt;Name&amp;gt;Nick Riviera&amp;lt;/Name&amp;gt;
&amp;lt;/Author&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But for this document:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Flight departureTime=&amp;quot;1pm&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might want a &lt;code&gt;%Flight{}&lt;/code&gt; struct.&lt;/p&gt;
&lt;p&gt;The only generic functionality is to manage the stack as you progress through a
document. However, the specific elements and what you want to pull out of a document
and put into the state you accumulate will be different. You really have only two options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a unique handler per document that accumulates all the data you want to pull
from the XML document.&lt;/li&gt;
&lt;li&gt;Have a generic handler used by every document, which puts everything into a generic XML
data structure.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Number 1 allows you to collect only the data you wish to pull from the XML and ignore the
rest but it requires writing a custom handler for each XML document.&lt;/p&gt;
&lt;p&gt;And number 2 — well, number 2 is a DOM 😅.&lt;/p&gt;
&lt;p&gt;By default, Saxy actually does number 2 —
&lt;a href=&quot;https://github.com/qcam/saxy/blob/master/lib/saxy/simple_form/handler.ex&quot;&gt;it creates a data structure called SimpleForm&lt;/a&gt;, a tuple DOM that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{node_name, attributes, children}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;children&lt;/code&gt; is a list of more tuple nodes or text — for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Blog&amp;gt;
  &amp;lt;Name&amp;gt;XML Parsing&amp;lt;/Name&amp;gt;
  &amp;lt;Author&amp;gt;
    &amp;lt;Name&amp;gt;Nick Riviera&amp;lt;/Name&amp;gt;
  &amp;lt;/Author&amp;gt;
&amp;lt;/Blog&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{&amp;quot;Blog&amp;quot;, [], [
  {&amp;quot;Name&amp;quot;, [], [&amp;quot;XML Parsing&amp;quot;]},
  {&amp;quot;Author&amp;quot;, [], [
    {&amp;quot;Name&amp;quot;, [], [&amp;quot;Nick Riviera&amp;quot;]}
  ]}
]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great...but haven&amp;#39;t we just run slap-bang into all of the DOM problems we mentioned
above? Well, almost. We are in full control of the created DOM, which means we
can be clever.&lt;/p&gt;
&lt;p&gt;The xmerl DOM we mentioned before is designed to enable XPath, but if we can live without
that (and I maintain that we can, nay, we can improve on it), we can significantly reduce
the size of the DOM we create.&lt;/p&gt;
&lt;p&gt;We need to be willing to do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Replace XPath with something.&lt;/li&gt;
&lt;li&gt;Design a more minimal DOM.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I have seen amazing improvements over xmerl doing just this; an order of magnitude
less memory and a latency improvement of the same.&lt;/p&gt;
&lt;p&gt;For 2, we can go with SimpleForm for now, but let&amp;#39;s look at what we can do about 1.&lt;/p&gt;
&lt;h2&gt;Querying the DOM with DataSchema&lt;/h2&gt;
&lt;p&gt;While a custom query engine may sound scary, it&amp;#39;s an opportunity to improve.
Opting to navigate a DOM in Elixir means we don&amp;#39;t have a black box XPath implementation
that just returns nil when it&amp;#39;s not happy (leaving you to figure out if the data wasn&amp;#39;t
there or if you just typed the path wrong).&lt;/p&gt;
&lt;p&gt;Usually, everything we ever need from the XML boils down to one of three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A node&lt;/li&gt;
&lt;li&gt;A node&amp;#39;s text&lt;/li&gt;
&lt;li&gt;A node&amp;#39;s attr&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We either want one, or many, of each of these things. We end up with an API that&amp;#39;s something
like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;get_text
get_attr
get_all_attrs
get_all_text
get_node
get_all_nodes
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;How DataSchema Works&lt;/h3&gt;
&lt;p&gt;To help improve the developer experience even further, I wrote &lt;a href=&quot;https://github.com/Adzz/data_schema/&quot;&gt;DataSchema&lt;/a&gt;.
DataSchema is like Ecto&amp;#39;s embedded schemas but generalized to any input type, including XML.&lt;/p&gt;
&lt;p&gt;It allows us to write declarative schemas that describe structs we can create from input data. For example, this is a schema for the XML snippet above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Blog&amp;gt;
  &amp;lt;Name&amp;gt;XML Parsing&amp;lt;/Name&amp;gt;
  &amp;lt;Author&amp;gt;
    &amp;lt;Name&amp;gt;Nick Riviera&amp;lt;/Name&amp;gt;
  &amp;lt;/Author&amp;gt;
&amp;lt;/Blog&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Blog do
  import DataSchema, only: [data_schema: 1]

  @data_accessor SimpleFormAccessor
  data_schema(
    field: {:title, [&amp;quot;Blog&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;text()&amp;quot;], StringType},
    field: {:author_name, [&amp;quot;Blog&amp;quot;, &amp;quot;Author&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;text()&amp;quot;], StringType},
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are some &lt;a href=&quot;https://github.com/Adzz/data_schema/tree/main/livebooks&quot;&gt;really good livebooks&lt;/a&gt;
in the repo to learn the library properly, but let&amp;#39;s break down the basics of the schema.&lt;/p&gt;
&lt;p&gt;Each field in a schema defines a key in a struct. You can see the key below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;field: {:title, [&amp;quot;Blog&amp;quot;,&amp;quot;Name&amp;quot;,&amp;quot;text()&amp;quot;], StringType},
 #      ^^^^^^^
 #  The struct key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next element in that tuple is a path to a piece of data in the XML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;field: {:title, [&amp;quot;Blog&amp;quot;,&amp;quot;Name&amp;quot;,&amp;quot;text()&amp;quot;], StringType},
 #                   ^^^^^^^
 #               Path to a value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are in full control of what that path can look like, but for now, I&amp;#39;ve opted to make it
a list of XML nodes that mirror what an XPath query would look like split on
&lt;code&gt;&amp;quot;/&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The last element in that tuple is a casting function. When we call:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;DataSchema.to_struct(xml, Blog)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DataSchema will get the value at the end of the path (for each field) and pass it to a
casting function. This gives us a chance to alter it in some way.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;field: {:title, [&amp;quot;Blog&amp;quot;,&amp;quot;Name&amp;quot;,&amp;quot;text()&amp;quot;], StringType},
 #                                         ^^^^^^^
 #                                    casting function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The casting function can be a module that implements a &lt;code&gt;cast/1&lt;/code&gt; function, an anonymous fn,
or a Mod Fun Args tuple.&lt;/p&gt;
&lt;p&gt;Finally, DataSchema needs to apply the path to the input data
it transforms.&lt;/p&gt;
&lt;p&gt;We provide a &lt;code&gt;@data_accessor&lt;/code&gt; in the schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...
@data_accessor SimpleFormAccessor
#                 ^^^^^^^^^
#              Accessor module
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This module will implement a callback that gets passed the path and the input data
(in our case, XML). The return value of that function is given to the casting
function.&lt;/p&gt;
&lt;p&gt;This accessor is where we can implement the traversal of the SimpleForm data structure.
This is relatively easy. Here is an example snippet getting
the text of an element:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def get_text([&amp;quot;text()&amp;quot;], {_, _, children}) do
  Enum.filter(children, &amp;amp;is_binary/1)
end

def get_text([node_name | rest], {node_name, _, children}) do
  get_text(rest, children)
end

def get_text([node_name | _], _) do
  {:error, &amp;quot;node not found #{node_name}&amp;quot;}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This small snippet demonstrates the improvement we can get over XPath because we can now log out the exact node that we could not find. This is a huge developer
experience productivity boost.&lt;/p&gt;
&lt;p&gt;All this comes together so that when we call &lt;code&gt;DataSchema.to_struct(xml, Blog)&lt;/code&gt;, it returns:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:ok, %Blog{title: &amp;quot;XML Parsing&amp;quot;, author_name: &amp;quot;Nick Riviera&amp;quot; }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the flow of data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;XML binary =&amp;gt;
  Saxy (to create a SimpleForm DOM) =&amp;gt;
    Query that DOM with DataSchema =&amp;gt;
      Struct
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;XML Parsing with Elixir: Taking it One Step Further&lt;/h3&gt;
&lt;p&gt;In the wild, I&amp;#39;ve found that the Saxy/DataSchema approach improves over the xmerl DOM by
order of magnitude. But we can go one step further.&lt;/p&gt;
&lt;p&gt;Our schemas are declarative
specifications of all the data we want from the XML. We can feed this information into a
saxy handler and &lt;em&gt;only&lt;/em&gt; include elements in the DOM that our schema needs.&lt;/p&gt;
&lt;p&gt;This nifty trick works out especially well for schemas where you only need a small amount
of the data in the XML document. If the data you end up with is larger in memory than the
DOM you build, you don&amp;#39;t need to worry about making the DOM smaller. But if it isn&amp;#39;t, then
building the DOM can cause waste and garbage, as you end up ignoring most of it.&lt;/p&gt;
&lt;p&gt;We need to transform our schema into a tree with the schema&amp;#39;s paths — e.g., for this &lt;code&gt;Blog&lt;/code&gt; schema:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Author do
  import DataSchema, only: [data_schema: 1]

  @data_accessor SimpleFormAccessor
  data_schema(
    field: {:name, [&amp;quot;Author&amp;quot;, &amp;quot;text()&amp;quot;], StringType},
  )
end

defmodule Blog do
  import DataSchema, only: [data_schema: 1]

  @data_accessor SimpleFormAccessor
  data_schema(
    field: {:title, [&amp;quot;Blog&amp;quot;, &amp;quot;Name&amp;quot;, &amp;quot;text()&amp;quot;], StringType},
    has_one: {:author, [&amp;quot;Blog&amp;quot;, &amp;quot;Author&amp;quot;], StringType},
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We would create a tree of paths that looks something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%{
  &amp;quot;Blog&amp;quot; =&amp;gt; %{
    &amp;quot;text()&amp;quot; =&amp;gt; true,
    &amp;quot;Author&amp;quot; =&amp;gt; %{
      &amp;quot;text()&amp;quot; =&amp;gt; true
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Handing that tree to the Saxy handler allows us to skip entire sub-trees of the XML.&lt;/p&gt;
&lt;p&gt;To demonstrate this, let&amp;#39;s parse the XML with the above schema.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Blog&amp;gt;
  &amp;lt;Comments&amp;gt;
    &amp;lt;Comment&amp;gt;Superb!&amp;lt;/Comment&amp;gt;
    &amp;lt;Comment&amp;gt;Amazing!&amp;lt;/Comment&amp;gt;
  &amp;lt;/Comments&amp;gt;
  &amp;lt;Name&amp;gt;XML Parsing&amp;lt;/Name&amp;gt;
  &amp;lt;Author&amp;gt;
    &amp;lt;Name&amp;gt;Nick Riviera&amp;lt;/Name&amp;gt;
  &amp;lt;/Author&amp;gt;
&amp;lt;/Blog&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, recall that the key to parsing in this manner is to create a stack of elements.
As you can see, when we
&lt;a href=&quot;https://github.com/qcam/saxy/blob/master/lib/saxy/simple_form/handler.ex&quot;&gt;build a SimpleForm DOM&lt;/a&gt;, we maintain a stack of nodes. When we get a &lt;code&gt;:start_element&lt;/code&gt; event,
we put that element onto the &lt;a href=&quot;https://github.com/qcam/saxy/blob/master/lib/saxy/simple_form/handler.ex#L14&quot;&gt;top of the stack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When we receive an &lt;code&gt;:end_element&lt;/code&gt; event, we put the element that is on the top of the stack
&lt;a href=&quot;https://github.com/qcam/saxy/blob/master/lib/saxy/simple_form/handler.ex#L44&quot;&gt;into the children&lt;/a&gt;
of the element below it (its parent).&lt;/p&gt;
&lt;p&gt;But this time our handler has a schema and therefore a record of the values we actually
care about. We can now query it every time we start a new element and
ask &amp;quot;is this element in the schema?&amp;quot;. If it is, we do as explained above and add it to the
stack. If it isn&amp;#39;t, we add a special node to the stack:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:skip, 1, tag_name}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we close a tag that we are skipping (i.e. when the top of the stack is that
tuple) then we just pop that &lt;code&gt;{:skip, 1, tag_name}&lt;/code&gt; element off of the stack and discard it.
But the real win is if we open another tag before that one closes — i.e. when we meet
the child of a skipped element.&lt;/p&gt;
&lt;p&gt;In the example above, it would go like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We open &lt;code&gt;&amp;lt;Comments&amp;gt;&lt;/code&gt; and see it is not in the schema, so we add &lt;code&gt;:skip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We get an event for the start of the &lt;code&gt;&amp;lt;Comment&amp;gt;&lt;/code&gt; tag. We see that the top of the stack is
a &lt;code&gt;:skip&lt;/code&gt; element, so we immediately return:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(:start_element, _element, [{:skip, _, _} | _] = stack) do
  {:ok, state}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This continues until we close &lt;code&gt;&amp;lt;Comments&amp;gt;&lt;/code&gt; and the &lt;code&gt;:skip&lt;/code&gt; element is removed. Then we
continue as normal.&lt;/p&gt;
&lt;p&gt;Okay, but what is that &lt;code&gt;1&lt;/code&gt; doing in the middle? This is effectively a reference count.
Consider this XML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Blog&amp;gt;
  &amp;lt;Comments&amp;gt;
    &amp;lt;Comments&amp;gt;
    &amp;lt;/Comments&amp;gt;
  &amp;lt;/Comments&amp;gt;
&amp;lt;/Blog&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While nasty, it&amp;#39;s perfectly valid XML that risks the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We add a &lt;code&gt;:skip&lt;/code&gt; tag for the opening of the first &lt;code&gt;&amp;lt;Comments&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The opening of the second &lt;code&gt;&amp;lt;Comments&amp;gt;&lt;/code&gt; is skipped.&lt;/li&gt;
&lt;li&gt;On the closing of the second &lt;code&gt;&amp;lt;Comments&amp;gt;&lt;/code&gt;, the name of the &amp;quot;skipped&amp;quot; tag matches this
one, so we remove the skipped element from the stack, even though we haven&amp;#39;t
actually finished skipping yet.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One solution to this is to add a &lt;code&gt;:skip&lt;/code&gt; tag for every element you want to skip. But then
you don&amp;#39;t save any memory, as you still end up with a stack of every element — you just
remove it more quickly. The memory will seem lower but will spike high during parsing.&lt;/p&gt;
&lt;p&gt;Instead, we&amp;#39;ll keep a count of elements with the same name as the
skipped element once we start skipping. Then, each time we close one of those elements, we
decrement the count. If it&amp;#39;s ever 0, we are done skipping and can remove the tag.&lt;/p&gt;
&lt;p&gt;This approach speeds up the latency of parsing a little, but importantly (along with some other
tricks) massively trims down the size of the SimpleForm DOM that gets created.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Adzz/data_schema/blob/saxy/lib/xml/saxy.ex&quot;&gt;See a version of the full Saxy handler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There is even more we could do in this vein. For example, this approach stores all nodes
along the path to the value we want. But if we just want the value at the end of the path,
could we keep that value and none of the intermediary nodes? This comes with its
own problems. We&amp;#39;ll leave discovering these problems as an exercise for you 🙂.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;This concludes our tour of some interesting ways to parse XML faster, including building a DOM, using a VTD, and SAX parsing. We also went one step further, feeding data into a
Saxy handler (including elements in the DOM needed by our schema).&lt;/p&gt;
&lt;p&gt;My hope is to one
day open source a complete implementation of the slimmed down Sax parser, but for now, I hope
this post has stimulated some of your own ideas.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Fix Process Bottlenecks with Elixir 1.14&#039;s Partition Supervisor</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/09/20/fix-process-bottlenecks-with-elixir-1-14s-partition-supervisor.html"/>
    <id>https://blog.appsignal.com/2022/09/20/fix-process-bottlenecks-with-elixir-1-14s-partition-supervisor.html</id>
    <published>2022-09-20T00:00:00+00:00</published>
    <updated>2022-09-20T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how partition supervisors work under the hood to prevent process bottlenecks and fix an example of a bottleneck.</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://elixir-lang.org/blog/2022/09/01/elixir-v1-14-0-released/&quot;&gt;Elixir v1.14&lt;/a&gt; shipped earlier this month with a bunch of new goodies.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll explore Elixir&amp;#39;s new &lt;code&gt;PartitionSupervisor&lt;/code&gt;. We&amp;#39;ll take a look at some code that suffers from the exact bottleneck issue that partitions supervisors are designed to solve. Then, we&amp;#39;ll fix that bottleneck. Along the way, you&amp;#39;ll learn how partition supervisors work under the hood to prevent process bottlenecks.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;The Problem: Dynamic Supervisor Bottlenecks in Your Elixir App&lt;/h2&gt;
&lt;p&gt;You may be familiar with using dynamic supervisors to start child processes on-demand in your application. Telling the dynamic supervisor to start its children can become a bottleneck, however.&lt;/p&gt;
&lt;p&gt;With just one dynamic supervisor, concurrent processes each have to wait their turn to tell your app to start up children. If the &amp;quot;start up child&amp;quot; process takes a long time, or your app handles a very high volume of &amp;quot;tell the dynamic supervisor to start children&amp;quot; requests, you&amp;#39;ve got a bottleneck. The single dynamic supervisor can only initialize one child process at a time.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at a simple example that artificially replicates such a bottleneck.&lt;/p&gt;
&lt;h3&gt;The Slow Worker and Its Dynamic Supervisor&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/sophiedebenedetto/slow_greeter&quot;&gt;my sample app here&lt;/a&gt;, I have a worker - &lt;a href=&quot;https://github.com/SophieDeBenedetto/slow_greeter/blob/main/lib/slow_greeter/worker.ex&quot;&gt;&lt;code&gt;SlowGreeter.Worker&lt;/code&gt;&lt;/a&gt;. The worker module is a genserver that initializes by sleeping for five seconds and then printing out a greeting:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SlowGreeter.Worker do
  use GenServer

  def start_link(%{name: name, from: from}) do
    GenServer.start_link(__MODULE__, %{name: name, from: from})
  end

  def init(state) do
    :timer.sleep(5000)
    send(self(), :greet)
    {:ok, state}
  end

  def handle_info(:greet, %{name: name, from: from}) do
    IO.puts(&amp;quot;Hello from #{from}, #{name}&amp;quot;)
    {:noreply, name}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This is meant to replicate a genserver with some time-consuming work to do on initialization. It should be noted that a &amp;quot;slow-starting&amp;quot; genserver is something of a code smell. You should avoid doing time-consuming work in the &lt;code&gt;#init/1&lt;/code&gt; function and leverage &lt;a href=&quot;https://elixirschool.com/blog/til-genserver-handle-continue/&quot;&gt;&lt;code&gt;handle_continue/2&lt;/code&gt;&lt;/a&gt; to prevent long-running tasks from blocking genserver start up.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;But, sometimes doing such work when the genserver starts up is unavoidable. And regardless, this setup helps us replicate a bottleneck scenario that can happen:&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;1. When your dynamic supervisor is either starting up a slow-to-initialize worker, or&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;2. If your app is handles many concurrent requests telling the same dynamic supervisor to start up its children.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Okay, with that disclaimer out of the way, let&amp;#39;s proceed with illustrating our bottleneck. We have our slow-to-initialize worker, and we also have a &lt;a href=&quot;https://github.com/SophieDeBenedetto/slow_greeter/blob/main/lib/slow_greeter/dynamic_supervisor.ex&quot;&gt;&lt;code&gt;SlowGreeter.DynamicSupervisor&lt;/code&gt; module&lt;/a&gt; that starts it up:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SlowGreeter.DynamicSupervisor do
  use DynamicSupervisor
  alias SlowGreeter.Worker

  def start_link(init_arg) do
    DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  @impl true
  def init(_init_arg) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end

  def start_greeter(name) do
    spec = %{id: Worker, start: {Worker, :start_link, [%{name: name, from: &amp;quot;DynamicSupervisor&amp;quot;}]}}
    DynamicSupervisor.start_child(__MODULE__, spec)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The &lt;code&gt;SlowGreeter.DynamicSupervisor&lt;/code&gt; &lt;a href=&quot;https://github.com/SophieDeBenedetto/slow_greeter/blob/main/lib/slow_greeter/application.ex#L14&quot;&gt;starts when the application starts up&lt;/a&gt;. Then, we can tell it to start the greeter worker like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;SlowGreeter.DynamicSupervisor.start_greeter(&amp;quot;Frankenstein&amp;quot;)
# sleep for 5 seconds...
&amp;quot;Hello from DynamicSupervisor, Frankenstein&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we&amp;#39;re ready to demonstrate our bottleneck.&lt;/p&gt;
&lt;h3&gt;Demo: The Bottleneck&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s spawn five processes, each of which will make a call to &lt;code&gt;SlowGreeter.DynamicSupervisor.start_greeter/1&lt;/code&gt;. Since each of our spawned processes requests the &lt;em&gt;same&lt;/em&gt; dynamic supervisor, we&amp;#39;ll see that each process must wait its turn.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;for _i &amp;lt;- 1..5 do
  name = Faker.Person.first_name()
  # The DynamicSupervisor starts a worker that sleeps for 5 seconds then puts a greeting
  spawn(fn -&amp;gt; SlowGreeter.DynamicSupervisor.start_greeter(name) end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the &lt;code&gt;SlowGreeter.DynamicSupervisor&lt;/code&gt; starts up its child &lt;code&gt;SlowGreeter.Worker&lt;/code&gt;, it must wait for the worker to initialize. The worker initialization process is slow--we told it to sleep for five seconds and then print out a greeting. We&amp;#39;ll see that each spawned process&amp;#39;s call to the dynamic supervisor is only processed when the preceding one finishes. As a result, each greeting prints out at a five-second interval, as you can see in this video:&lt;/p&gt;
&lt;Video fileName=&quot;/images/blog/2022-09/bottleneck&quot; /&gt;

&lt;p&gt;This approach is bottlenecked by the dynamic supervisor itself. It can only process one &amp;quot;start up child&amp;quot; request at a time, and must wait until the initialization of a child worker is complete before moving on to the next one.&lt;/p&gt;
&lt;p&gt;We can remove this bottleneck with the help of Elixir 1.14&amp;#39;s new &lt;code&gt;PartitionSupervisor&lt;/code&gt;. Let&amp;#39;s implement it now. Then, we&amp;#39;ll take a deeper dive into how it works.&lt;/p&gt;
&lt;h2&gt;The Fix: Supervise a Fleet of Dynamic Supervisors with a Partition Supervisor&lt;/h2&gt;
&lt;p&gt;Instead of initializing just one dynamic supervisor when our application starts up, we&amp;#39;ll use the new &lt;code&gt;PartitionSupervisor&lt;/code&gt; to spin up a set of dynamic supervisors.&lt;/p&gt;
&lt;p&gt;Then, instead of making direct calls to the dynamic supervisor to start its child worker, we will go &lt;em&gt;through&lt;/em&gt; the partition supervisor, which will route the request to one of the many dynamic supervisors it&amp;#39;s overseeing. Let&amp;#39;s take a look at the code.&lt;/p&gt;
&lt;h3&gt;Using &lt;code&gt;PartitionSupervisor&lt;/code&gt; in the Dynamic Supervisor Module&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll implement a new module, &lt;a href=&quot;https://github.com/SophieDeBenedetto/slow_greeter/blob/main/lib/slow_greeter/dynamic_supervisor_with_partition.ex&quot;&gt;&lt;code&gt;SlowGreeter.DynamicSupervisorWithPartition&lt;/code&gt;&lt;/a&gt;, which uses the &lt;code&gt;DynamicSupervisor&lt;/code&gt; behaviour. This time, however, the &lt;code&gt;#start_greeter/1&lt;/code&gt; function will call on the dynamic supervisor to start its child &lt;em&gt;via&lt;/em&gt; the &lt;code&gt;PartitionSupervisor&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SlowGreeter.DynamicSupervisorWithPartition do
  use DynamicSupervisor
  alias SlowGreeter.Worker

  def start_link(init_arg) do
    DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  @impl true
  def init(_init_arg) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end

  def start_greeter(name) do
    spec = %{id: Worker, start: {Worker, :start_link, [%{name: name, from: &amp;quot;PartitionSupervisor&amp;quot;}]}}

    DynamicSupervisor.start_child(
      {:via, PartitionSupervisor, {__MODULE__, self()}},
      spec
    )
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s where the magic happens:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;DynamicSupervisor.start_child(
  {:via, PartitionSupervisor, {__MODULE__, self()}},
  spec
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of calling on the &lt;code&gt;SlowGreeter.DynamicSupervisorWithPartition&lt;/code&gt; directly, we call it through the partition supervisor using the &lt;code&gt;{:via, PartitionSupervisor, {dynamic_supervisor_name, routing_key}}&lt;/code&gt; tuple.&lt;/p&gt;
&lt;p&gt;This will route the &amp;quot;start child request&amp;quot; to one of the running &lt;code&gt;SlowGreeter.DynamicSupervisorWithPartition&lt;/code&gt; processes supervised by the partition supervisor that starts up with our application. Let&amp;#39;s configure our app to start such a supervisor now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# application.ex
def start(_type, _args) do
  children = [
      {PartitionSupervisor, child_spec: DynamicSupervisor, name: SlowGreeter.DynamicSupervisorWithPartition},
    ]

    opts = [strategy: :one_for_one, name: SlowGreeter.Supervisor]
    Supervisor.start_link(children, opts)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, when the app starts, a partition supervisor will start up and begin supervising a set of &lt;code&gt;SlowGreeter.DynamicSupervisorWithPartition&lt;/code&gt; dynamic supervisors. The default behavior is to create a partition for each available scheduler (usually one per core of your machine). It will then place a dynamic supervisor on each partition.&lt;/p&gt;
&lt;p&gt;With our code in place, let&amp;#39;s see a demo of our bottleneck fix.&lt;/p&gt;
&lt;h3&gt;Demo: No More Bottleneck&lt;/h3&gt;
&lt;p&gt;Once again, we&amp;#39;ll spawn five processes. Each process will call on the &lt;code&gt;SlowGreeter.DynamicSupervisorWithPartition#start_greeter/1&lt;/code&gt; function, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;for _i &amp;lt;- 1..5 do
  name = Faker.Person.first_name()
  # The PartitionSupervisor tells one of its dynamic supervisors to start a worker that sleeps for 5 seconds then puts a greeting
  spawn(fn -&amp;gt; SlowGreeter.DynamicSupervisorWithPartition.start_greeter(name) end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function goes &lt;em&gt;through&lt;/em&gt; the partition supervisor to route a &amp;quot;start child worker&amp;quot; request to dynamic supervisors across partitions. This means we don&amp;#39;t have to wait for a single dynamic supervisor to finish initializing a child worker before moving on to process the next request from a spawned process.&lt;/p&gt;
&lt;p&gt;Instead, the partition supervisor will route these requests so that they&amp;#39;re processed more or less concurrently by the dynamic supervisors spread across partitions. So, we&amp;#39;ll see that all five greetings are printed out simultaneously after just &lt;em&gt;one&lt;/em&gt; five-second sleep. You can see this behavior in the video below:&lt;/p&gt;
&lt;Video fileName=&quot;/images/blog/2022-09/partition-supervisor&quot; /&gt;

&lt;p&gt;With that, we&amp;#39;ve fixed our bottleneck! Remember that our worker&amp;#39;s &amp;quot;sleep for five seconds on init&amp;quot; behavior is artificial, and you&amp;#39;ll want to avoid lengthy worker startups in general. But, this example serves to illustrate the kind of bottleneck that can occur in your application if you deal with lots of concurrent requests to the same dynamic supervisor.&lt;/p&gt;
&lt;p&gt;Elixir 1.14&amp;#39;s new partition supervisor neatly solves this problem by partitioning your dynamic supervisors and distributing requests to them, so that they can handle a greater load.&lt;/p&gt;
&lt;p&gt;Where you don&amp;#39;t need to share state between child processes supervised by dynamic supervisors, this approach can help your dynamic supervisors handle scale and avoid bottlenecks.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve seen partition supervisors in action, let&amp;#39;s take a closer look at how they work.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;PartitionSupervisor&lt;/code&gt; in Elixir 1.14: Under the Hood&lt;/h2&gt;
&lt;p&gt;Keep reading for a deeper dive into how partition supervisors establish partitions and route requests to dynamic supervisors.&lt;/p&gt;
&lt;h3&gt;Partitioning Dynamic Supervisors&lt;/h3&gt;
&lt;p&gt;As we saw earlier, you can tell your app to start a partition supervisor, overseeing some dynamic supervisors, in your &lt;code&gt;application.ex&lt;/code&gt;&amp;#39;s &lt;code&gt;#start/2&lt;/code&gt; function like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def start(_type, _args) do
  children = [
    {PartitionSupervisor, child_spec: DynamicSupervisor, name: SlowGreeter.DynamicSupervisorWithPartition},
  ]

  opts = [strategy: :one_for_one, name: SlowGreeter.Supervisor]
  Supervisor.start_link(children, opts)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we start a partition supervisor that starts a &lt;code&gt;SlowGreeter.DynamicSupervisorWithPartition&lt;/code&gt; for each core in our machine. This is the default &lt;code&gt;start_link&lt;/code&gt; behavior.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PartitionSupervisor#start_link/1&lt;/code&gt; supports options that include a &lt;code&gt;:partitions&lt;/code&gt; key. The &lt;code&gt;:partitions&lt;/code&gt; key should be set to a positive integer representing the number of partitions and defaults to &lt;code&gt;System.schedulers_online()&lt;/code&gt;, which should return the number of cores on your machine.&lt;/p&gt;
&lt;p&gt;Under the hood, a partition supervisor is just a regular supervisor that generates a child spec for each partition and then stores the partition info in ETS or a Registry. Later, when you tell a dynamic supervisor to start its child via the partition supervisor, it selects a partition based on the routing algorithm and routes the call to a dynamic supervisor in that partition. So, it effectively spins up a set of dynamic supervisors when your app comes up, and then starts child processes across those dynamic supervisors.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a closer look at the routing behavior now.&lt;/p&gt;
&lt;h3&gt;Routing Requests to Dynamic Supervisors&lt;/h3&gt;
&lt;p&gt;When you&amp;#39;re ready to start a dynamic supervisor&amp;#39;s child through a partition supervisor, you do so like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;DynamicSupervisor.start_child(
  {:via, PartitionSupervisor, {dynamic_supervisor_name, routing_key}},
  spec
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;:via&lt;/code&gt; tuple specifies the name of the dynamic supervisor to start up and a routing key.&lt;/p&gt;
&lt;p&gt;In our example app, we used &lt;code&gt;self()&lt;/code&gt; as a routing key, which will return the PID of the current process, but you can also provide a positive integer here. If key is an integer, it is routed using &lt;code&gt;rem(abs(key), num_partitions)&lt;/code&gt;. Otherwise, the routing is performed by calling &lt;code&gt;:erlang.phash2(key, num_partitions)&lt;/code&gt;. So, when you use the same PID as a routing key, you can be assured that your call will be directed to the same partition every time.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve seen how you can use partition supervisors to avoid bottlenecks in your dynamic supervisor code. Provided the state of your child processes can be partitioned (i.e., you don&amp;#39;t need to share state among them), you can reach for a partition supervisor to elegantly scale up your dynamic supervisors.&lt;/p&gt;
&lt;p&gt;In fact, partition supervisors can be used to partition and scale any process in your Elixir application. If a process can be started up, and have its state partitioned, then you can use a partition supervisor. Start the partition supervisor with its child spec (just like we did for our dynamic supervisor) and dispatch messages to the partition supervisor&amp;#39;s children using the same &lt;code&gt;:via&lt;/code&gt; tuple we demonstrated.&lt;/p&gt;
&lt;p&gt;This is just one of the many exciting new features of Elixir v1.14. &lt;a href=&quot;https://blog.appsignal.com/2022/09/13/elixir-1-14-better-debugging-with-dbg-and-more&quot;&gt;Read about another new feature, debugging with &lt;code&gt;dbg()&lt;/code&gt;&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Elixir 1.14: Better Debugging with dbg/2 and More</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/09/13/elixir-1-14-better-debugging-with-dbg-and-more.html"/>
    <id>https://blog.appsignal.com/2022/09/13/elixir-1-14-better-debugging-with-dbg-and-more.html</id>
    <published>2022-09-13T00:00:00+00:00</published>
    <updated>2022-09-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s check out Elixir 1.14&#039;s improvements to `Inspect` and binary evaluation error messaging, as well as the new `dbg()` debugging function.</summary>
    <content type="html">&lt;p&gt;The latest Elixir release introduces new features to improve your developer and debugging experience.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll take a look at the new &lt;code&gt;dbg()&lt;/code&gt; functionality, along with some improvements to &lt;code&gt;Inspect&lt;/code&gt; and binary evaluation error messaging. All these changes come together to make you an even more productive Elixirist.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Debugging with &lt;code&gt;Kernel.dbg/2&lt;/code&gt; in Elixir&lt;/h2&gt;
&lt;p&gt;The Elixir Kernel now exposes a &lt;code&gt;dbg/2&lt;/code&gt; macro that you can use with or without IEx for enhanced debugging. Let&amp;#39;s walk through a few examples that illustrate just how useful this tool can be in your debugging toolkit.&lt;/p&gt;
&lt;p&gt;In this example, we have a Phoenix LiveView application called Live Library. Users can browse, checkout, and return books. Unfortunately for us, however, it looks like we have a bug--when a user tries to check out a book, the live view crashes:&lt;/p&gt;
&lt;Video fileName=&quot;/images/blog/2022-09/livelibrary&quot; /&gt;

&lt;p&gt;We can use the &lt;code&gt;dbg/2&lt;/code&gt; function to gain insight into what&amp;#39;s going wrong. We&amp;#39;ll start with a few well-placed calls to &lt;code&gt;dbg/2&lt;/code&gt;. Then, we&amp;#39;ll move on to leveraging &lt;code&gt;dbg/2&lt;/code&gt; within an IEx session.&lt;/p&gt;
&lt;h3&gt;Debugging the Current Binding&lt;/h3&gt;
&lt;p&gt;First, we&amp;#39;ll make a call to &lt;code&gt;dbg/2&lt;/code&gt; in the live view&amp;#39;s event handler function that gets called when the user clicks &amp;quot;checkout&amp;quot;. This is the entry point of our &amp;quot;checkout book&amp;quot; code flow, so we&amp;#39;ll start our debugging process there.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/live_library_web/live/book_live/checkout_component.ex

def handle_event(&amp;quot;checkout&amp;quot;, _, %{assigns: %{book: book}} = socket) do
  dbg() # this is new!
  case Library.checkout_book(book, socket.assigns.current_user.id) do
    {:ok, book} -&amp;gt;
      {:noreply, socket |&amp;gt; assign(:book, book)}

    {:err, _err} -&amp;gt;
      {:noreply, socket}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if we try once again to check out a book, we&amp;#39;ll see the following output in our terminal where we&amp;#39;re running the Phoenix server via &lt;code&gt;mix phx.server&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[(live_library 0.1.0) lib/live_library_web/live/book_live/checkout_component.ex:33: LiveLibraryWeb.CheckoutComponent.handle_event/3]
binding() #=&amp;gt; [
  book: %LiveLibrary.Library.Book{
    updated_at: ~N[2022-09-11 17:42:19],
    inserted_at: ~N[2022-02-28 16:33:45],
    book_loans: [
      %LiveLibrary.Library.BookLoan{
        updated_at: ~N[2022-09-11 17:39:18],
        inserted_at: ~N[2022-09-11 17:39:18],
        book_id: 7,
        user_id: 4,
        id: 51,
        __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, &amp;quot;book_loans&amp;quot;&amp;gt;
      }
    ],
    author_id: 4,
    title: &amp;quot;My Test Book!!!&amp;quot;,
    description: &amp;quot;A book I made up. Different from the book I wrote which I also technically made up.&amp;quot;,
    cover: &amp;quot;live_view_upload-1657544569-150520820351856-7&amp;quot;,
    available: true,
    id: 7,
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, &amp;quot;books&amp;quot;&amp;gt;
  },
  socket: #Phoenix.LiveView.Socket&amp;lt;
    id: &amp;quot;phx-FxPfPGQDjqGwUAyB&amp;quot;,
    endpoint: LiveLibraryWeb.Endpoint,
    view: LiveLibraryWeb.BookLive.Index,
    parent_pid: nil,
    root_pid: #PID&amp;lt;0.780.0&amp;gt;,
    router: LiveLibraryWeb.Router,
    assigns: %{
      __changed__: %{},
      book: %LiveLibrary.Library.Book{
        updated_at: ~N[2022-09-11 17:42:19],
        inserted_at: ~N[2022-02-28 16:33:45],
        # ...
      },
      current_user: #LiveLibrary.Accounts.User&amp;lt;
        updated_at: ~N[2022-02-18 14:49:02],
        inserted_at: ~N[2022-02-18 14:49:02],
        admin: true,
        confirmed_at: nil,
        email: &amp;quot;admin@email.com&amp;quot;,
        id: 4,
        __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, &amp;quot;users&amp;quot;&amp;gt;,
        ...
      &amp;gt;,
      flash: %{},
      id: &amp;quot;checkout-7&amp;quot;,
      myself: %Phoenix.LiveComponent.CID{cid: 5}
    },
    transport_pid: #PID&amp;lt;0.768.0&amp;gt;,
    # ...
  &amp;gt;
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When called without any arguments, &lt;code&gt;dbg/2&lt;/code&gt; defaults to debugging the binding for the current context. In this case, that&amp;#39;s the &lt;code&gt;handle_event/3&lt;/code&gt; function (and the variables available to us by the time the &lt;code&gt;dbg/2&lt;/code&gt; call is hit on the first line of that function).&lt;/p&gt;
&lt;p&gt;As you can see in the output above, calling &lt;code&gt;dbg/2&lt;/code&gt; does a few things for us - printing out the:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Location of the debugged code:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[(live_library 0.1.0) lib/live_library_web/live/book_live/checkout_component.ex:33: LiveLibraryWeb.CheckoutComponent.handle_event/3]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Value of the current context&amp;#39;s binding:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;binding() #=&amp;gt; [
  book: %LiveLibrary.Library.Book{
    #...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The call to &lt;code&gt;dbg/2&lt;/code&gt; also &lt;em&gt;returns the value of the debugged code itself&lt;/em&gt;. We&amp;#39;ll see how helpful this is in a bit.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;For now, we&amp;#39;re already experiencing some of the benefits of &lt;code&gt;dbg/2&lt;/code&gt; with just this basic usage. Let&amp;#39;s examine the value of the arguments that &lt;code&gt;handle_event/3&lt;/code&gt; is called with. This way, we&amp;#39;ll better understand how our code is executing and what might be going wrong.&lt;/p&gt;
&lt;p&gt;Based on the &lt;code&gt;dbg/2&lt;/code&gt; output, it looks like the input to &lt;code&gt;handle_event/3&lt;/code&gt; is exactly what we expect. We have a socket whose &lt;code&gt;assigns&lt;/code&gt; correctly contain a book and a current user. So, let&amp;#39;s move our call to &lt;code&gt;dbg/2&lt;/code&gt; downstream a bit, into the &lt;code&gt;Library.checkout_book/2&lt;/code&gt; context function.&lt;/p&gt;
&lt;h3&gt;Debugging Provided Code&lt;/h3&gt;
&lt;p&gt;At this point in our debugging journey, we&amp;#39;re ready to turn our attention to the behavior of the &lt;code&gt;Library.checkout_book/2&lt;/code&gt; function. This is the next step in our broken &amp;quot;checkout book&amp;quot; code flow.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re interested in a few things. We&amp;#39;d like to understand what exact arguments the function is being called with, and what it returns. We can easily reveal this information with two calls to &lt;code&gt;debug/2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll call &lt;code&gt;dbg/2&lt;/code&gt; with the current default context at the beginning of the &lt;code&gt;checkout_book/2&lt;/code&gt; function to look at the arguments&amp;#39; values.&lt;/p&gt;
&lt;p&gt;Then, we&amp;#39;ll pipe the code in &lt;code&gt;Library.checkout_book/2&lt;/code&gt; into a call to &lt;code&gt;dbg/2&lt;/code&gt; at the &lt;em&gt;end&lt;/em&gt; of the function. This will allow us to see the return value of the function. And, since &lt;code&gt;dbg/2&lt;/code&gt; returns the value of the executed code you pass to it as a first argument, the remainder of our &amp;quot;checkout book&amp;quot; code flow will be unaffected by this call to &lt;code&gt;dbg/2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s what our debugged function looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def checkout_book(book, user_id) do
  dbg()
  with {:ok, _loan} &amp;lt;- Library.create_book_loan(%{user_id: user_id, book_id: book.id}),
       {:ok, book} &amp;lt;- Library.update_book(book, %{available: false}) do
        book
  else
    err -&amp;gt; err
  end
  |&amp;gt; dbg()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if we try to check out a book, we&amp;#39;ll see the following output in our terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[(live_library 0.1.0) lib/live_library/library.ex:13: LiveLibrary.Library.checkout_book/2]
binding() #=&amp;gt; [
  book: %LiveLibrary.Library.Book{
    updated_at: ~N[2022-09-11 18:27:59],
    inserted_at: ~N[2022-02-28 16:33:45],
    author_id: 4,
    title: &amp;quot;My Test Book!!!&amp;quot;,
    description: &amp;quot;A book I made up. Different from the book I wrote which I also technically made up.&amp;quot;,
    cover: &amp;quot;live_view_upload-1657544569-150520820351856-7&amp;quot;,
    available: true,
    id: 7,
    __meta__: #Ecto.Schema.Metadata&amp;lt;:loaded, &amp;quot;books&amp;quot;&amp;gt;,
    # ...
  },
  user_id: 4
]

# ...

[(live_library 0.1.0) lib/live_library/library.ex:21: LiveLibrary.Library.checkout_book/2]
with {:ok, _loan} &amp;lt;- Library.create_book_loan(%{user_id: user_id, book_id: book.id}),
     {:ok, book} &amp;lt;- Library.update_book(book, %{available: false}) do
  book
else
  err -&amp;gt; err
end #=&amp;gt;
%LiveLibrary.Library.Book{
  updated_at: ~N[2022-09-11 18:28:00],
  inserted_at: ~N[2022-02-28 16:33:45],
  # ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From this, we can clearly see that the &lt;code&gt;checkout_book/2&lt;/code&gt; function returns a single book struct. We&amp;#39;re close to solving our bug now.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s return to the &lt;code&gt;handle_event/3&lt;/code&gt; function that calls &lt;code&gt;checkout_book/2&lt;/code&gt;. This time, we&amp;#39;ll run our server in an IEx session with &lt;code&gt;iex -S mix phx.server&lt;/code&gt;. Then, we&amp;#39;ll place another &lt;code&gt;dbg/2&lt;/code&gt; call in the &lt;code&gt;handle_event/3&lt;/code&gt; function to freeze code execution and interact with our code in real time.&lt;/p&gt;
&lt;h3&gt;Debugging with &lt;code&gt;dbg/2&lt;/code&gt; and IEx in Elixir&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;dbg/2&lt;/code&gt; function is configurable, and you can extend it with advanced behavior. IEx comes with one such extension baked in.&lt;/p&gt;
&lt;p&gt;In Elixir 1.14, IEx extends &lt;code&gt;dbg/2&lt;/code&gt; with an interactive shell, similar to &lt;code&gt;IEx.pry&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s add back our &lt;code&gt;dbg/2&lt;/code&gt; call to the event handler function and play around:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/live_library_web/live/book_live/checkout_component.ex

def handle_event(&amp;quot;checkout&amp;quot;, _, %{assigns: %{book: book}} = socket) do
  dbg()
  case Library.checkout_book(book, socket.assigns.current_user.id) do
    {:ok, book} -&amp;gt;
      {:noreply, socket |&amp;gt; assign(:book, book)}

    {:err, _err} -&amp;gt;
      {:noreply, socket}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when we try to check out a book in the browser, we&amp;#39;ll see that we have a request to pry in our terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Request to pry #PID&amp;lt;0.816.0&amp;gt; at LiveLibraryWeb.CheckoutComponent.handle_event/3 (lib/live_library_web/live/book_live/checkout_component.ex:33)

   32:   def handle_event(&amp;quot;checkout&amp;quot;, _, %{assigns: %{book: book}} = socket) do
   33:     dbg()
   34:     case Library.checkout_book(book, socket.assigns.current_user.id) do
   35:       {:ok, book} -&amp;gt;
   36:         Endpoint.broadcast(@checkout_topic, &amp;quot;checkout_event&amp;quot;, %{book: book})

Allow? [Yn] Y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can now interact with and execute our code. Let&amp;#39;s manually execute the &lt;code&gt;checkout_book/2&lt;/code&gt; function like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;pry(1)&amp;gt; Library.checkout_book(book, socket.assigns.current_user.id)
iex(1)&amp;gt; [debug] QUERY OK db=1.0ms idle=1240.2ms
INSERT INTO &amp;quot;book_loans&amp;quot; (&amp;quot;book_id&amp;quot;,&amp;quot;user_id&amp;quot;,&amp;quot;inserted_at&amp;quot;,&amp;quot;updated_at&amp;quot;) VALUES ($1,$2,$3,$4) RETURNING &amp;quot;id&amp;quot; [7, 4, ~N[2022-09-11 18:46:06], ~N[2022-09-11 18:46:06]]
[debug] QUERY OK db=1.0ms queue=0.3ms idle=1241.5ms
UPDATE &amp;quot;books&amp;quot; SET &amp;quot;available&amp;quot; = $1, &amp;quot;updated_at&amp;quot; = $2 WHERE &amp;quot;id&amp;quot; = $3 [false, ~N[2022-09-11 18:46:06], 7]
%LiveLibrary.Library.Book{
  updated_at: ~N[2022-09-11 18:46:06],
  inserted_at: ~N[2022-02-28 16:33:45],
  # ...
  ],
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we can see that we are returning the newly checked-out book. A call to &lt;code&gt;whereami&lt;/code&gt; will show us the next bit of code flow that will try to execute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;pry(2)&amp;gt; whereami
Location: lib/live_library_web/live/book_live/checkout_component.ex:33

   31:
   32:   def handle_event(&amp;quot;checkout&amp;quot;, _, %{assigns: %{book: book}} = socket) do
   33:     dbg()
   34:     case Library.checkout_book(book, socket.assigns.current_user.id) do
   35:       {:ok, book} -&amp;gt;

    (live_library 0.1.0) lib/live_library_web/live/book_live/checkout_component.ex:33: LiveLibraryWeb.CheckoutComponent.handle_event/3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This reminds us that the case statement expects to match on a return value &lt;em&gt;not&lt;/em&gt; of a single book struct, but rather of an &lt;code&gt;{:ok, book}&lt;/code&gt; tuple. With that, we&amp;#39;ve found our bug! By updating the &lt;code&gt;checkout_book/2&lt;/code&gt; function to return a tuple instead of a book struct, we&amp;#39;ll fix our problem.&lt;/p&gt;
&lt;p&gt;Before we move on to some other new Elixir 1.14 features that will improve your development and debugging experience, let&amp;#39;s take a last look at some additional &lt;code&gt;dbg/2&lt;/code&gt; functionality.&lt;/p&gt;
&lt;h3&gt;More &lt;code&gt;dbg/2&lt;/code&gt; Goodies&lt;/h3&gt;
&lt;p&gt;Let&amp;#39;s examine how &lt;code&gt;dbg/2&lt;/code&gt; makes it easier than ever before to debug pipelines. Then, we&amp;#39;ll peek at some of the more advanced &lt;code&gt;dbg/2&lt;/code&gt; configuration capabilities.&lt;/p&gt;
&lt;h3&gt;Debugging Pipelines with &lt;code&gt;dbg/2&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;dbg/2&lt;/code&gt; macro makes it easier to debug pipelines. Before &lt;code&gt;dbg/2&lt;/code&gt;, if you wanted to examine return values at each step of your pipeline, you&amp;#39;d have to add an explicit call to &lt;code&gt;IO.inspect&lt;/code&gt; at each step - like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/live_library_web/live/book_live/index.ex
def mount(_params, %{&amp;quot;user_token&amp;quot; =&amp;gt; user_token}, socket) do
  {:ok,
   socket
   |&amp;gt; assign_user(user_token)
   |&amp;gt; IO.inspect()
   |&amp;gt; assign_books()
   |&amp;gt; IO.inspect()
   |&amp;gt; assign_search()
   |&amp;gt; IO.inspect()
   |&amp;gt; assign_search_changeset()
   |&amp;gt; IO.inspect()
   |&amp;gt; assign_categories()
   |&amp;gt; IO.inspect()
   |&amp;gt; assign_category_ids()}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn&amp;#39;t very eloquent and it can be tedious to implement. Now in Elixir 1.14, we can place just one call to &lt;code&gt;dgb/2&lt;/code&gt; at the end of our pipeline. This will print out the value at each individual step of the pipeline and ensure that the pipeline still returns the value of the executed code. Let&amp;#39;s add in our &lt;code&gt;dbg/2&lt;/code&gt; call here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def mount(_params, %{&amp;quot;user_token&amp;quot; =&amp;gt; user_token}, socket) do
  {:ok,
   socket
   |&amp;gt; assign_user(user_token) # %{assigns: %{user: #...}}
   |&amp;gt; assign_books() # %{assigns: %{books: #...}}
   |&amp;gt; assign_search() # %{assigns: %{search: #...}}
   |&amp;gt; assign_search_changeset() # # %{assigns: %{search_changeset: #...}}
   |&amp;gt; assign_categories() # %{assigns: %{categories: #...}}
   |&amp;gt; assign_category_ids() # %{assigns: %{category_ids: #...}}
   |&amp;gt; dbg()}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when we visit the &lt;code&gt;/books&lt;/code&gt; index page that brings up this live view, we&amp;#39;ll see that the return value of each step of the pipeline has been printed for us to examine.&lt;/p&gt;
&lt;p&gt;Additionally, if you run this code in an IEx session, you will be able to step, or pry, through each individual step in the pipeline. Code execution will freeze at each successive line in the pipeline.&lt;/p&gt;
&lt;p&gt;Pipelines represent one of Elixir&amp;#39;s most powerful and eloquent language features, and debugging them just got easier.&lt;/p&gt;
&lt;h3&gt;Configuring &lt;code&gt;dbg/2&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;You can extend the behavior of &lt;code&gt;dbg/2&lt;/code&gt; in your Elixir application by defining a custom function. Tell &lt;code&gt;dbg/2&lt;/code&gt; to use that custom function via your app&amp;#39;s &lt;code&gt;:dbg_callback&lt;/code&gt; configuration key. Your app configuration should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/config.exs
config :elixir, :dbg_callback, {MyMod, :debug_fun, [:stdio]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where you&amp;#39;ve defined a function &lt;code&gt;MyMod.debug_fun/4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then when &lt;code&gt;dbg/2&lt;/code&gt; is called, your custom function will be called with three arguments prepended to any arguments you specify in your app config:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An AST representing the code to be debugged that was passed to &lt;code&gt;dbg/2&lt;/code&gt; as a first argument.&lt;/li&gt;
&lt;li&gt;An AST representing any options given to &lt;code&gt;dbg/2&lt;/code&gt; as a second argument.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Macro.Env&lt;/code&gt; struct representing the context in which &lt;code&gt;dbg/2&lt;/code&gt; was invoked.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can find a more detailed example of this &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#dbg/2-configuring-the-debug-function&quot;&gt;&lt;code&gt;dbg/2&lt;/code&gt; custom configuration approach in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve taken a pretty comprehensive look at what &lt;code&gt;dbg/2&lt;/code&gt; has to offer, let&amp;#39;s move on to some other new Elixir 1.14 features that improve the development experience.&lt;/p&gt;
&lt;h2&gt;Inspect Improvements&lt;/h2&gt;
&lt;p&gt;Elixir 1.14 has improved the &lt;code&gt;Inspect&lt;/code&gt; protocol implementation for a few core library modules: &lt;code&gt;MapSet&lt;/code&gt;, &lt;code&gt;Version.Requirement&lt;/code&gt;, and &lt;code&gt;Date.Range&lt;/code&gt;. Previously, calls to inspect a new &lt;code&gt;MapSet&lt;/code&gt; would return notation that is not valid Elixir:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; MapSet.new([1, :two, {&amp;quot;three&amp;quot;}])
#MapSet&amp;lt;[1, :two, {&amp;quot;three&amp;quot;}]&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This output can&amp;#39;t be copied and pasted in IEx, or operated on by subsequent function calls.&lt;/p&gt;
&lt;p&gt;This is no longer the case in Elixir 1.14. Now, you&amp;#39;ll see this behavior:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; MapSet.new([1, :two, {&amp;quot;three&amp;quot;}])
MapSet.new([1, :two, {&amp;quot;three&amp;quot;}])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the output &lt;em&gt;is&lt;/em&gt; valid Elixir that can be operated on by subsequent Elixir code.&lt;/p&gt;
&lt;p&gt;Some additional improvements have been made to &lt;code&gt;Inspect&lt;/code&gt; protocol for structs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When you inspect a struct, fields will be displayed in the order in which they are defined in &lt;code&gt;defstruct&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you want to customize the &lt;code&gt;Inspect&lt;/code&gt; behavior for your struct by deriving it, you can use the new &lt;code&gt;:optional&lt;/code&gt; keyword to omit struct fields that have not changed from their default value when displaying the inspection results. This simplifies struct representation and adds some much-needed brevity to the representation of larger structs. You can learn more info about the &lt;a href=&quot;https://hexdocs.pm/elixir/Inspect.html#module-deriving&quot;&gt;&lt;code&gt;Inspect&lt;/code&gt; customization option in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have just one more Elixir 1.14 improvement to look at before we wrap up.&lt;/p&gt;
&lt;h2&gt;Better Binary Evaluation Errors&lt;/h2&gt;
&lt;p&gt;In keeping with the improved debugging and developer experience we see throughout the Elixir 1.14 release, the latest version of Elixir also improves error messaging on binary construction and evaluation. This brings Elixir in line with Erlang/OTP 25 improvements in the same area.&lt;/p&gt;
&lt;p&gt;Instead of getting generic &lt;code&gt;ArgumentError&lt;/code&gt; messages when constructing binaries in an invalid manner, we get more informative error messages like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; 123 &amp;lt;&amp;gt; &amp;quot;456&amp;quot;
** (ArgumentError) expected binary argument in &amp;lt;&amp;gt; operator but got: 123
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Want to learn how you can also save time debugging an app in production with AppSignal? &lt;a href=&quot;https://www.appsignal.com/customers/upside&quot;&gt;Check out how Upside does it&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;Elixir has a devoted following and an increasingly growing community and adoption rate, in part because the language prioritizes developer happiness.&lt;/p&gt;
&lt;p&gt;This latest Elixir release is no exception. With new debugging capabilities and improvements to &lt;code&gt;Inspect&lt;/code&gt; protocols as well as binary evaluation error messages, Elixir&amp;#39;s developer experience toolkit has grown even more.&lt;/p&gt;
&lt;p&gt;Thanks to these new features, you&amp;#39;ll be more productive in Elixir than ever before. Upgrade your Elixir apps today, and get going!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Benchmark Your Elixir App&#039;s Performance with Benchee</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/09/06/benchmark-your-elixir-apps-performance-with-benchee.html"/>
    <id>https://blog.appsignal.com/2022/09/06/benchmark-your-elixir-apps-performance-with-benchee.html</id>
    <published>2022-09-06T00:00:00+00:00</published>
    <updated>2022-09-06T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Explore how you can benchmark an Elixir application using Benchee and test the app&#039;s performance.</summary>
    <content type="html">&lt;p&gt;At some point, every software engineer will find themselves in a situation where they need to benchmark system performance and test the limits of what a given system can handle. This is a common problem in software engineering, and even more so in the applications that are well suited for Elixir.&lt;/p&gt;
&lt;p&gt;Finding bottlenecks early on in an application can save a lot of time, money, and effort in the long run, and give developers confidence in the upper limit of a system.&lt;/p&gt;
&lt;p&gt;In this post, we will introduce a tool called &lt;code&gt;Benchee&lt;/code&gt; to benchmark parts of an Elixir application. We will also show you how to integrate Benchee with your automated test suite.&lt;/p&gt;
&lt;p&gt;By the end of the article, you&amp;#39;ll understand Benchee&amp;#39;s full functionality and capabilities, and will be able to use it to measure your application&amp;#39;s performance.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Why Do I Need to Benchmark My Elixir Application?&lt;/h2&gt;
&lt;p&gt;Benchmarking, in a nutshell, is the process of measuring the performance of a system under specific loads or conditions. As part of the benchmarking process, you will be able to identify potential bottlenecks in your system and areas to improve.&lt;/p&gt;
&lt;p&gt;For example, we can use benchmarking tools to answer questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Can a system handle ten times the load of normal traffic?&lt;/li&gt;
&lt;li&gt;Can the system run on a smaller infrastructure to handle the same load?&lt;/li&gt;
&lt;li&gt;How long does it take to process 10, 100, 1,000, or 10,000 requests? Does the processing time scale linearly with the number of requests?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just answering these questions alone can help your team avoid costly mistakes and proactively identify areas for improvement, avoiding downtime and unhappy users.&lt;/p&gt;
&lt;p&gt;Benchmarking doesn&amp;#39;t have to be expensive or time-consuming; it can be simple to get the right tools in place and make them part of an application&amp;#39;s natural development life cycle.&lt;/p&gt;
&lt;h2&gt;What Is Benchee?&lt;/h2&gt;
&lt;p&gt;This is where &lt;a href=&quot;https://github.com/bencheeorg/benchee&quot;&gt;Benchee&lt;/a&gt; comes in. Benchee is a tool that you can use to benchmark parts of an Elixir application. It is versatile and extensible, with more than a few &lt;a href=&quot;https://github.com/bencheeorg/benchee#plugins&quot;&gt;plugins&lt;/a&gt; to enhance its functionality.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;h3&gt;Elixir Environment&lt;/h3&gt;
&lt;p&gt;To follow along, you will need to locally install Elixir and Phoenix. The easiest way to do so is to follow the &lt;a href=&quot;https://elixir-lang.org/install.html&quot;&gt;official Elixir instructions&lt;/a&gt;, which will give you a couple of options for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Local installation on Linux, Windows, and macOS&lt;/li&gt;
&lt;li&gt;Dockerized versions of Elixir&lt;/li&gt;
&lt;li&gt;Package manager version setups&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I recommend a local installation for the best results.&lt;/p&gt;
&lt;h3&gt;Setting Up Our Elixir Application&lt;/h3&gt;
&lt;p&gt;For this article&amp;#39;s purposes, we will set up a simple Elixir application that can calculate the Fibonacci sequence.&lt;/p&gt;
&lt;p&gt;Start by creating a new application with &lt;code&gt;mix new fibonacci_benchmarking&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;As output, you will see the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/fibonacci_benchmarking.ex
* creating test
* creating test/test_helper.exs
* creating test/fibonacci_benchmarking_test.exs

Your Mix project was created successfully.
You can use &amp;quot;mix&amp;quot; to compile it, test it, and more:

    cd fibonacci_benchmarking
    mix test

Run &amp;quot;mix help&amp;quot; for more commands.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, in your favorite editor, add the following code to the &lt;code&gt;lib/fibonacci_benchmarking.ex&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FibonacciBenchmarking do
  def list(number), do: Enum.map(0..number, &amp;amp;fibonacci/1)

  def fibonacci(0), do: 0
  def fibonacci(1), do: 1
  def fibonacci(n), do: fibonacci(0, 1, n-2)

  def fibonacci(_, prv, -1), do: prv
  def fibonacci(prvprv, prv, n) do
      next = prv + prvprv
      fibonacci(prv, next, n-1)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: The original code can be found in &lt;a href=&quot;https://rosettacode.org/wiki/Fibonacci_sequence#Elixir&quot;&gt;rosettacode.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Go to the &lt;code&gt;fibonacci_benchmarking&lt;/code&gt; directory and run the following commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix deps.get
iex -S mix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And once inside the elixir shell, you can run this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; FibonacciBenchmarking.list(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you see the above output, you have successfully set up your application, and are ready to proceed with Benchee.&lt;/p&gt;
&lt;h2&gt;Implement Benchmarking on an Elixir Application&lt;/h2&gt;
&lt;p&gt;First, we will need to install Benchee. Start by adding the following to your &lt;code&gt;mix.exs&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:benchee, &amp;quot;~&amp;gt; 1.0&amp;quot;, only: :dev}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can validate that Benchee is installed by running the Elixir shell and the following snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Benchee.run(%{
    &amp;quot;10_seq&amp;quot; =&amp;gt; fn -&amp;gt; FibonacciBenchmarking.list(10) end
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Benchee might take a second or two to warm up, but on completion, you should see the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Operating System: Linux
CPU Information: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
Number of Available Cores: 8
Available memory: 62.76 GB
Elixir 1.13.3
Erlang 24.2.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 7 s

Benchmarking 10_seq ...

Name             ips        average  deviation         median         99th %
10_seq      973.04 K        1.03 μs  ±2735.15%        0.77 μs        1.60 μs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above makes a call to &lt;code&gt;FibonacciBenchmarking.list(10)&lt;/code&gt;, and Benchee measures the time it takes to execute the function.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a moment to understand the output of Benchee. By default, Benchee will output the following information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ips&lt;/strong&gt; stands for iterations per second. This number represents how many times a given function can be executed in a second. &lt;strong&gt;Higher is better&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;average&lt;/strong&gt; is the average time it takes to execute the function. &lt;strong&gt;Lower is better&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;deviation&lt;/strong&gt; is the standard deviation of the results. This is a measure of how much the results deviate from the average.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;median&lt;/strong&gt; is the middle value of the results.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;99th %&lt;/strong&gt; - 99% of all the measured values are less than this value.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While running Benchee in this fashion can be useful for ad-hoc benchmarks, a much better method is to include Benchee as part of our unit tests.&lt;/p&gt;
&lt;h2&gt;Automate Benchee for Elixir and Run Tests&lt;/h2&gt;
&lt;p&gt;By default, all Elixir and Phoenix applications have a &lt;code&gt;test&lt;/code&gt; directory and use &lt;code&gt;ExUnit&lt;/code&gt; to run tests. Our goal is to get Benchee running as part of our test suite and test a different implementation of the Fibonacci sequence.&lt;/p&gt;
&lt;p&gt;Start by creating a new file called &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt;, and copy the following code into it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BencheeUnitTest do
  use ExUnit.Case
  alias Application.TestHelper

  @tag :benchmark
  test &amp;quot;benchmark fibonacci list generation&amp;quot; do
    # capture benchee output to run assertions
    output = Benchee.run(%{
      &amp;quot;case_10_numbers&amp;quot; =&amp;gt; fn() -&amp;gt;
        FibonacciBenchmarking.list(10)
      end
    })

    results = Enum.at(output.scenarios, 0)
    assert results.run_time_data.statistics.average &amp;lt;= 50_000_000
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Go ahead and run &lt;code&gt;mix test&lt;/code&gt; on the console. Validate that the output looks like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Operating System: Linux
CPU Information: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
Number of Available Cores: 8
Available memory: 62.76 GB
Elixir 1.13.3
Erlang 24.2.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 7 s

Benchmarking case_10_numbers ...

Name                      ips        average  deviation         median         99th %
case_10_numbers        1.31 M      765.77 ns  ±3552.51%         599 ns        1165 ns
.

Finished in 10.7 seconds (0.00s async, 10.7s sync)
1 test, 0 failures

Randomized with seed 612867
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far, we have integrated Benchee into our test suite and added the first test to validate one of the test cases. Let&amp;#39;s add the second test case to compare. Update the &lt;code&gt;test&lt;/code&gt; function to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BencheeUnitTest do
  use ExUnit.Case
  alias Application.TestHelper

  @tag :benchmark
  test &amp;quot;benchmark fibonacci list generation&amp;quot; do
    # capture benchee output to run assertions
    output = Benchee.run(%{
      &amp;quot;case_10_numbers&amp;quot; =&amp;gt; fn() -&amp;gt;
        FibonacciBenchmarking.list(10)
      end,
      &amp;quot;case_1000_numbers&amp;quot; =&amp;gt; fn() -&amp;gt;
        FibonacciBenchmarking.list(1000)
      end
    })

    results = Enum.at(output.scenarios, 0)
    assert results.run_time_data.statistics.average &amp;lt;= 50_000_000
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just like we did before, we can run the test suite with &lt;code&gt;mix test&lt;/code&gt;, and validate that the output looks like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Operating System: Linux
CPU Information: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
Number of Available Cores: 8
Available memory: 62.76 GB
Elixir 1.13.3
Erlang 24.2.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: none specified
Estimated total run time: 14 s

Benchmarking case_1000_numbers ...
Benchmarking case_10_numbers ...

Name                        ips        average  deviation         median         99th %
case_10_numbers          1.33 M     0.00075 ms  ±3419.36%     0.00059 ms     0.00109 ms
case_1000_numbers     0.00010 M       10.21 ms    ±11.54%        9.83 ms       15.29 ms

Comparison:
case_10_numbers          1.33 M
case_1000_numbers     0.00010 M - 13598.03x slower +10.21 ms
.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our second test scenario tries to compare the performance of the Fibonacci sequence with a list of 1,000 numbers; however, this is not a very practical way to test with multiple inputs. We can take advantage of the &lt;code&gt;Benchee.run&lt;/code&gt; hooks and provide a list of inputs for each scenario.&lt;/p&gt;
&lt;p&gt;Go ahead and open the &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt; file and replace the contents with this code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BencheeUnitTest do
  use ExUnit.Case
  alias Application.TestHelper

  @tag :benchmark
  test &amp;quot;benchmark fibonacci list generation&amp;quot; do
    # capture benchee output to run assertions
    output = Benchee.run(%{
      &amp;quot;generate_list&amp;quot; =&amp;gt; fn(input) -&amp;gt;
        FibonacciBenchmarking.list(input)
      end
    },
    inputs: %{
      &amp;quot;case_10&amp;quot; =&amp;gt; 10,
      &amp;quot;case_100&amp;quot; =&amp;gt; 100,
      &amp;quot;case_1000&amp;quot; =&amp;gt; 1000,
      &amp;quot;case_10000&amp;quot; =&amp;gt; 10000,
      &amp;quot;case_100000&amp;quot; =&amp;gt; 100000
    })

    results = Enum.at(output.scenarios, 0)
    assert results.run_time_data.statistics.average &amp;lt;= 50_000_000
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this new version of the code, we have generalized our generate list case to accept a list of inputs, and we can now run the test suite with &lt;code&gt;mix test&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, because of the size of our last input, you will get a message like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;❯ mix test

Operating System: Linux
CPU Information: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
Number of Available Cores: 8
Available memory: 62.76 GB
Elixir 1.13.3
Erlang 24.2.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: case_10, case_100, case_1000, case_10000, case_100000
Estimated total run time: 35 s

Benchmarking generate_list with input case_10 ...
Benchmarking generate_list with input case_100 ...
Benchmarking generate_list with input case_1000 ...
Benchmarking generate_list with input case_10000 ...
Benchmarking generate_list with input case_100000 ...


  1) test benchmark fibonacci list generation (BencheeUnitTest)
     test/benchee_unit_test.exs:6
     ** (ExUnit.TimeoutError) test timed out after 60000ms. You can change the timeout:

       1. per test by setting &amp;quot;@tag timeout: x&amp;quot; (accepts :infinity)
       2. per test module by setting &amp;quot;@moduletag timeout: x&amp;quot; (accepts :infinity)
       3. globally via &amp;quot;ExUnit.start(timeout: x)&amp;quot; configuration
       4. by running &amp;quot;mix test --timeout x&amp;quot; which sets timeout
       5. or by running &amp;quot;mix test --trace&amp;quot; which sets timeout to infinity
          (useful when using IEx.pry/0)

     where &amp;quot;x&amp;quot; is the timeout given as integer in milliseconds (defaults to 60_000).

     code: output = Benchee.run(%{
     stacktrace:
       (elixir 1.13.3) lib/task.ex:794: Task.await/2
       (elixir 1.13.3) lib/enum.ex:1593: Enum.&amp;quot;-map/2-lists^map/1-0-&amp;quot;/2
       (benchee 1.1.0) lib/benchee/benchmark/runner.ex:77: Benchee.Benchmark.Runner.parallel_benchmark/2
       (elixir 1.13.3) lib/enum.ex:1593: Enum.&amp;quot;-map/2-lists^map/1-0-&amp;quot;/2
       (elixir 1.13.3) lib/enum.ex:1593: Enum.&amp;quot;-map/2-lists^map/1-0-&amp;quot;/2
       (benchee 1.1.0) lib/benchee/benchmark.ex:103: Benchee.Benchmark.collect/3
       (benchee 1.1.0) lib/benchee.ex:48: Benchee.run/2
       test/benchee_unit_test.exs:8: (test)
       (ex_unit 1.13.3) lib/ex_unit/runner.ex:500: ExUnit.Runner.exec_test/1
       (stdlib 3.17) timer.erl:166: :timer.tc/1
       (ex_unit 1.13.3) lib/ex_unit/runner.ex:451: anonymous fn/4 in ExUnit.Runner.spawn_test_monitor/4



Finished in 60.0 seconds (0.00s async, 60.0s sync)
1 test, 1 failure

Randomized with seed 567196
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As it happens, we hit a timeout error after 60 seconds. Fortunately, as part of the stack trace, we get a couple of suggestions on how to solve this problem. For now, update the test suite with this code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BencheeUnitTest do
  use ExUnit.Case
  alias Application.TestHelper

  @tag :benchmark
  @tag timeout: :infinity
  test &amp;quot;benchmark fibonacci list generation&amp;quot; do
    # capture benchee output to run assertions
    output = Benchee.run(%{
      &amp;quot;generate_list&amp;quot; =&amp;gt; fn(input) -&amp;gt;
        FibonacciBenchmarking.list(input)
      end
    },
    inputs: %{
      &amp;quot;case_10&amp;quot; =&amp;gt; 10,
      &amp;quot;case_100&amp;quot; =&amp;gt; 100,
      &amp;quot;case_1000&amp;quot; =&amp;gt; 1000,
      &amp;quot;case_10000&amp;quot; =&amp;gt; 10000,
      &amp;quot;case_100000&amp;quot; =&amp;gt; 100000
    })

    results = Enum.at(output.scenarios, 0)
    assert results.run_time_data.statistics.average &amp;lt;= 50_000_000
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: Depending on your system, running that last scenario will take a while; feel free to remove it to continue with the tutorial.&lt;/p&gt;
&lt;p&gt;Now that we have a baseline of our Fibonacci sequence generator&amp;#39;s performance, a common and useful exercise is to compare the performance of different implementations of the same algorithm. In this case, we have an alternative implementation of the Fibonacci sequence generator based on a recursive function.&lt;/p&gt;
&lt;p&gt;Start by updating the &lt;code&gt;lib/fibonacci_benchmarking.ex&lt;/code&gt; file with the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FibonacciBenchmarking do
  def list(number), do: Enum.map(0..number, &amp;amp;fibonacci/1)
  def list_alternate(number), do: Stream.unfold({0,1}, fn {a,b} -&amp;gt; {a,{b,a+b}} end) |&amp;gt; Enum.take(number)

  def fibonacci(0), do: 0
  def fibonacci(1), do: 1
  def fibonacci(n), do: fibonacci(0, 1, n-2)

  def fibonacci(_, prv, -1), do: prv
  def fibonacci(prvprv, prv, n) do
      next = prv + prvprv
      fibonacci(prv, next, n-1)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Following that, we will update the &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt; file to account for both implementations:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BencheeUnitTest do
  use ExUnit.Case

  @tag :benchmark
  @tag timeout: :infinity
  test &amp;quot;benchmark fibonacci list generation&amp;quot; do
    # capture benchee output to run assertions
    output = Benchee.run(%{
      &amp;quot;generate_list_enum&amp;quot; =&amp;gt; fn(input) -&amp;gt;
        FibonacciBenchmarking.list(input)
      end,
      &amp;quot;generate_list_stream&amp;quot; =&amp;gt; fn(input) -&amp;gt;
        FibonacciBenchmarking.list_alternate(input)
      end
    },
    inputs: %{
      &amp;quot;case_10&amp;quot; =&amp;gt; 10,
      &amp;quot;case_100&amp;quot; =&amp;gt; 100,
      &amp;quot;case_1000&amp;quot; =&amp;gt; 1000,
      &amp;quot;case_10000&amp;quot; =&amp;gt; 10000,
    })

    results = Enum.at(output.scenarios, 0)
    assert results.run_time_data.statistics.average &amp;lt;= 50_000_000
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The update test case will run two scenarios side by side for each of the prescribed inputs, letting us compare their overall performance. Go ahead and run &lt;code&gt;mix test&lt;/code&gt; to see the results.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Compiling 1 file (.ex)
Operating System: Linux
CPU Information: Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
Number of Available Cores: 8
Available memory: 62.76 GB
Elixir 1.13.3
Erlang 24.2.2

Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
reduction time: 0 ns
parallel: 1
inputs: case_10, case_100, case_1000, case_10000
Estimated total run time: 56 s

Benchmarking generate_list_enum with input case_10 ...
Benchmarking generate_list_enum with input case_100 ...
Benchmarking generate_list_enum with input case_1000 ...
Benchmarking generate_list_enum with input case_10000 ...
Benchmarking generate_list_stream with input case_10 ...
Benchmarking generate_list_stream with input case_100 ...
Benchmarking generate_list_stream with input case_1000 ...
Benchmarking generate_list_stream with input case_10000 ...

##### With input case_10 #####
Name                           ips        average  deviation         median         99th %
generate_list_stream        1.66 M      601.29 ns  ±3858.34%         441 ns         955 ns
generate_list_enum          1.35 M      742.83 ns  ±3201.26%         610 ns        1164 ns

Comparison:
generate_list_stream        1.66 M
generate_list_enum          1.35 M - 1.24x slower +141.55 ns

##### With input case_100 #####
Name                           ips        average  deviation         median         99th %
generate_list_stream      258.49 K        3.87 μs   ±512.17%        3.29 μs        8.04 μs
generate_list_enum         31.71 K       31.54 μs    ±26.84%       30.57 μs       41.17 μs

Comparison:
generate_list_stream      258.49 K
generate_list_enum         31.71 K - 8.15x slower +27.67 μs

##### With input case_1000 #####
Name                           ips        average  deviation         median         99th %
generate_list_stream       17.67 K      0.0566 ms    ±14.14%      0.0550 ms      0.0988 ms
generate_list_enum         0.102 K        9.84 ms     ±9.92%        9.60 ms       14.14 ms

Comparison:
generate_list_stream       17.67 K
generate_list_enum         0.102 K - 173.90x slower +9.78 ms

##### With input case_10000 #####
Name                           ips        average  deviation         median         99th %
generate_list_stream        501.16      0.00200 s    ±33.05%      0.00190 s      0.00370 s
generate_list_enum            0.27         3.75 s    ±12.05%         3.75 s         4.06 s

Comparison:
generate_list_stream        501.16
generate_list_enum            0.27 - 1876.93x slower +3.74 s
.

Finished in 65.3 seconds (0.00s async, 65.3s sync)
1 test, 0 failures

Randomized with seed 839542
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, our list function&amp;#39;s Enum implementation is much slower than the &lt;code&gt;Stream&lt;/code&gt; implementation, especially when the input size is larger. Comparing the performance of the two implementations is valuable in understanding the trade-offs and will help you develop more performant applications.&lt;/p&gt;
&lt;p&gt;When adding benchmarking tests to parts of your automated testing, consider the potential drawbacks, such as the increased time it takes to run the tests. In this case, the benchmarking tests are tagged with &lt;code&gt;:benchmark&lt;/code&gt; and can be excluded from the default test suite. This allows us to run the benchmarking tests separately from the unit tests and only when we need to.&lt;/p&gt;
&lt;p&gt;A much better approach is to take advantage of CI/CD pipeline integration like GitHub Actions and run the benchmarking tests as part of the pull request validation process. This way, we can run the benchmarking tests as part of the CI/CD pipeline and get the results without having to run the tests locally.&lt;/p&gt;
&lt;h2&gt;Improving Benchee Reporting&lt;/h2&gt;
&lt;p&gt;Now, while seeing results on the console can be useful for a quick glance, the console is not the most convenient way to share results with your team. Benchee provides a number of different ways to export your results to a file.&lt;/p&gt;
&lt;p&gt;For this example, we will use &lt;code&gt;benchee_html&lt;/code&gt; to generate an HTML report with our benchmarking test results. To do this, we will add the &lt;code&gt;benchee_html&lt;/code&gt; dependency to our &lt;code&gt;mix.exs&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def deps do
  [
    ...
    {:benchee_html, &amp;quot;~&amp;gt; 1.0&amp;quot;, only: [:dev, :test]}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we will update the &lt;code&gt;test/benchee_unit_test.exs&lt;/code&gt; file to generate the HTML report:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BencheeUnitTest do
  use ExUnit.Case

  @tag :benchmark
  @tag timeout: :infinity
  test &amp;quot;benchmark fibonacci list generation&amp;quot; do
    # capture benchee output to run assertions
    output = Benchee.run(%{
      &amp;quot;generate_list_enum&amp;quot; =&amp;gt; fn(input) -&amp;gt;
        FibonacciBenchmarking.list(input)
      end,
      &amp;quot;generate_list_stream&amp;quot; =&amp;gt; fn(input) -&amp;gt;
        FibonacciBenchmarking.list_alternate(input)
      end
    },
    inputs: %{
      &amp;quot;case_10&amp;quot; =&amp;gt; 10,
      &amp;quot;case_100&amp;quot; =&amp;gt; 100,
      &amp;quot;case_1000&amp;quot; =&amp;gt; 1000,
      &amp;quot;case_10000&amp;quot; =&amp;gt; 10000,
    },
    formatters: [
      Benchee.Formatters.HTML,
      Benchee.Formatters.Console
    ])

    results = Enum.at(output.scenarios, 0)
    assert results.run_time_data.statistics.average &amp;lt;= 50_000_000
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s go ahead and run the tests again:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mix test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On completion, you should see the following report open in your browser:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-09/report-index.png&quot; alt=&quot;Benchee HTML Report&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The HTML report provides a much more detailed view of the benchmarking results and allows us to share results with our team easily. For example:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-09/run-time-comparison.png&quot; alt=&quot;Run Time Comparison&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In addition to the HTML report, Benchee also supports exporting results to JSON, CSV, and XML formats. Exporting results to a file is a great way to integrate them with automation, such as CI/CD pipelines.&lt;/p&gt;
&lt;h2&gt;Monitoring Your Elixir App in Production&lt;/h2&gt;
&lt;p&gt;Benchee can help you discover potential performance bottlenecks, but what about how fast things really are in your production app?&lt;/p&gt;
&lt;p&gt;To be able to discover new and existing bottlenecks, and solve bugs and other issues your users may face, you need to use an APM. &lt;a href=&quot;https://www.appsignal.com/tour/performance&quot;&gt;AppSignal has been supporting Elixir developers for years and seamlessly integrates with your app&lt;/a&gt;. Bonus: We&amp;#39;re the only APM that ships stroopwafels to new users 😎&lt;/p&gt;
&lt;h1&gt;Wrapping Up and Next Steps&lt;/h1&gt;
&lt;p&gt;In this tutorial, we discovered how to benchmark Elixir applications with the Benchee library.&lt;/p&gt;
&lt;p&gt;We also learned how to compare the performance of different implementations of the same algorithm.&lt;/p&gt;
&lt;p&gt;Yet we have only scratched the surface of Benchee&amp;#39;s capabilities. As a next step, I highly encourage you to explore the available Benchee configuration options and visualization plugins.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Predictable Code in Elixir: Expressions as Reducers and Macros</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/08/23/predictable-code-in-elixir-expressions-as-reducers-and-macros.html"/>
    <id>https://blog.appsignal.com/2022/08/23/predictable-code-in-elixir-expressions-as-reducers-and-macros.html</id>
    <published>2022-08-23T00:00:00+00:00</published>
    <updated>2022-08-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of our two-part series, discover how to write expressions as reducers and use macros to keep your code predictable in Elixir.</summary>
    <content type="html">&lt;p&gt;In the &lt;a href=&quot;https://blog.appsignal.com/2022/07/19/writing-predictable-elixir-code-with-reducers.html&quot;&gt;first part of this series on maintainable Elixir code&lt;/a&gt;, we started by applying rules for code predictability in our code design. We
immediately saw an emerging pattern: a series of transformations on state. In this part, we&amp;#39;ll explore this pattern further.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll first learn how to write expressions as reducers. Then we&amp;#39;ll use metaprogramming to make use
of reducers and enforce code style seamlessly.&lt;/p&gt;
&lt;p&gt;Finishing up, we&amp;#39;ll see an example where all the pieces fit together.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Quick Recap of Part One and What We&amp;#39;ll Do&lt;/h2&gt;
&lt;p&gt;In the first part, we experimented with applying code styles to this snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;with %Payment{} = payment &amp;lt;- fetch_payment_information(params),
     {:ok, user} &amp;lt;- Session.get(conn, :user),
     address when !is_nil(address) &amp;lt;- fetch_address(user, params),
     {:ok, order} &amp;lt;- create_order(user, payment, address) do
  conn
  |&amp;gt; put_flash(:info, &amp;quot;Order completed!&amp;quot;)
  |&amp;gt; render(&amp;quot;checkout.html&amp;quot;)
else
  {:error, :payment_failed} -&amp;gt;
    handle_error(conn, &amp;quot;Payment Error&amp;quot;)

  %Store.OrderError{message: message} -&amp;gt;
    handle_error(conn, &amp;quot;Order Error&amp;quot;)

  error -&amp;gt;
    handle_error(conn, &amp;quot;Unprocessable order&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By the end of this post, we&amp;#39;ll have all the tools to rewrite it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;case Checkout.execute(%{params: params}, options) do
  {:ok, %{order: order}} -&amp;gt;
    conn
    |&amp;gt; put_flash(:info, &amp;quot;Order completed!&amp;quot;)
    |&amp;gt; redirect(to: Routes.order_path(conn, order))

  {:error, error}
    conn
    |&amp;gt; put_flash(:error, parse_error(error_description))
    |&amp;gt; render(&amp;quot;checkout.html&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While writing this post, I created &lt;a href=&quot;https://github.com/msramos/ex_pipeline&quot;&gt;ex_pipeline&lt;/a&gt;, an open source
library that allows developers to create pipelines while enforcing code style easily.&lt;/p&gt;
&lt;p&gt;All code examples in this
post are simplified versions of what exists in that project.&lt;/p&gt;
&lt;h2&gt;Chain of Transformations&lt;/h2&gt;
&lt;p&gt;One of my favorite hobbies is woodworking — I&amp;#39;m not good at it, by all means, but it&amp;#39;s something that I do enjoy. Before
starting a new project, I always write down all the materials and tools I&amp;#39;ll need, as well as the steps I&amp;#39;ll follow. That&amp;#39;s how I go from pieces of wood to a finished table, from an initial state to a finished state.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s think about how a table is made: you get some raw materials — wood, nails, glue — and a few tools. Then you
execute a set of actions to modify the shape and appearance of the materials — cutting, assembling, polishing, and
painting.&lt;/p&gt;
&lt;p&gt;You apply a &lt;em&gt;chain of transformations&lt;/em&gt; on an initial state (raw materials) until you get the desired state (the table).&lt;/p&gt;
&lt;p&gt;We already talked about the emerging pattern of a &lt;em&gt;pipeline&lt;/em&gt;. That&amp;#39;s what we are going to explore over the next
paragraphs.&lt;/p&gt;
&lt;h2&gt;Writing Expressions as Reducers in Elixir&lt;/h2&gt;
&lt;p&gt;Reducers are one of the key concepts of functional programming. They are very simple to understand: you take a list
of values, apply a function to each element, and accumulate the results.&lt;/p&gt;
&lt;p&gt;In Elixir, we can work with reducers using the &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html#reduce/3&quot;&gt;&lt;code&gt;Enum.reduce/3&lt;/code&gt;&lt;/a&gt;
function and its variants — &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html#reduce/2&quot;&gt;&lt;code&gt;Enum.reduce/2&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Enum.html#reduce_while/3&quot;&gt;&lt;code&gt;Enum.reduce_while/3&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, we can use a reducer to filter all even numbers from a list:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;numbers = [1, 2, 3, 4, 5, 6]
starting_value = []

Enum.reduce(numbers, starting_value, fn current_number, filtered_values -&amp;gt;
  if rem(current_number, 2) == 0 do   # is the current number even?
    [number | filtered_values]        # if so, add it to the accumulator
  else                                # otherwise...
    filtered_values                   # just ignore it and return the accumulator
  end
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will return the list &lt;code&gt;[2, 4, 6]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To execute different actions on a value, we can transform the list of values into a list of functions. Then we
pass the value as the initial value for the accumulator:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;transformations = [
  fn x -&amp;gt; x + 1 end, # add 1
  fn x -&amp;gt; x * 2 end  # multiply by two
]
starting_value = 10

Enum.reduce(transformations, starting_value, fn transformation, current_value -&amp;gt;
  apply(transformation, [current_value])
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks like a complicated way to write &lt;code&gt;(10 + 1) * 2&lt;/code&gt;, right? But by expressing each transformation as a
function, we can attach an arbitrary number of transformations. They all must accept the same number of parameters and return the next updated state. In other words, these functions must look the same and be small.&lt;/p&gt;
&lt;p&gt;In the end, we want to write the previous example as something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyModule do
  use Pipeline

  def sum_step(value, _), do: {:ok, value + 1}
  def double_step(value, _), do: {:ok, value * 2}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the next part, we can do just that using a bit of magic from macros!&lt;/p&gt;
&lt;h2&gt;Sewing Reducers Into Features with Macros&lt;/h2&gt;
&lt;p&gt;Now that we know how to use reducers let&amp;#39;s use them to write pipelines.&lt;/p&gt;
&lt;p&gt;The goal is to make the process of writing, reading, and maintaining pipelines as easy as possible. So, instead of adding
a &lt;a href=&quot;https://opensource.com/article/20/2/domain-specific-languages&quot;&gt;DSL&lt;/a&gt; or using complex configs, we just want to
write our functions using the same pattern of name and arity. We can then automate the process of building the pipeline by
detecting which functions follow this pattern.&lt;/p&gt;
&lt;p&gt;We create a new pipeline by &lt;em&gt;writing code on the same pattern&lt;/em&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;The State: Track What&amp;#39;s Happening in Elixir&lt;/h2&gt;
&lt;p&gt;Before we dive into macros, let&amp;#39;s take a step back and talk a little bit about the &lt;em&gt;state&lt;/em&gt; of the pipeline.&lt;/p&gt;
&lt;p&gt;When executing a pipeline, we need to know a few things: the initial state, the current state, if it&amp;#39;s still
valid, and if there are any errors. All this information will help us debug and troubleshoot any problems we might find
when writing our code.&lt;/p&gt;
&lt;p&gt;Also, by abstracting state updates in this module, we can enforce a very important rule on reducers: the return value
must be an ok/error tuple.&lt;/p&gt;
&lt;p&gt;The starting point of a module that manages state should be something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Pipeline.State do
  defstruct [:initial_value, :value, :valid?, :errors]

  def new(value) do
    %Pipeline.State{valid?: true, initial_value: value, value: value, errors: []}
  end

  def update(state, {module, function_name} = _function_definition, options \\ []) do
    case apply(module, function_name, [state.value, options]) do
      {:ok, value} -&amp;gt;
        %Pipeline.State{state | value: value}

      {:error, error_description} -&amp;gt;
        %Pipeline.State{state | valid?: false, errors: [error_description | state.errors]}

      bad_return -&amp;gt;
        raise &amp;quot;Unexpected return value for pipeline step: #{inspect(bad_return)}&amp;quot;
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;new/1&lt;/code&gt; function will create a new valid and clean &lt;code&gt;%Pipeline.State{}&lt;/code&gt; struct based on the initial value we
give to the pipeline executor.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;update/3&lt;/code&gt; function will update or invalidate the given state by calling &lt;code&gt;function&lt;/code&gt; with the state&amp;#39;s &lt;code&gt;value&lt;/code&gt; and
the given &lt;code&gt;options&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If the given &lt;code&gt;function&lt;/code&gt; returns an &lt;code&gt;{:ok, &amp;lt;updated_value&amp;gt;}&lt;/code&gt;, then the state&amp;#39;s &lt;code&gt;value&lt;/code&gt; is updated,
and we are good to go. However, if the &lt;code&gt;function&lt;/code&gt; returns an &lt;code&gt;{:error, &amp;lt;error&amp;gt;}&lt;/code&gt; value, the state is invalidated. The returned error is added to the list of errors in the state. If the function returns anything that&amp;#39;s different from an
ok/error tuple, it will raise an exception.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/msramos/ex_pipeline/blob/090200bda9e3aeb43dd8bdc9892cde7200e6a1ab/lib/pipeline/state.ex&quot;&gt;See the full implementation of this module&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Pipeline Steps and Hooks&lt;/h2&gt;
&lt;p&gt;Each function that transforms the state will be called a &lt;em&gt;step&lt;/em&gt;. Here are some guidelines to follow:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;em&gt;step&lt;/em&gt; is a function whose name ends with &lt;code&gt;_step&lt;/code&gt; and accepts two parameters.&lt;/li&gt;
&lt;li&gt;Steps execute in the order they are declared in their module.&lt;/li&gt;
&lt;li&gt;If one step fails, then all remaining steps are ignored.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sometimes, we still want to execute code, even during failures — write a log, update a trace, publish a message, etc. We have a special type of step for these cases: a &lt;em&gt;hook&lt;/em&gt;. Let&amp;#39;s list the guidelines for hooks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;em&gt;hook&lt;/em&gt; is a function whose name ends with &lt;code&gt;_hook&lt;/code&gt; and accepts two parameters.&lt;/li&gt;
&lt;li&gt;Hooks execute in the order they are declared, just like &lt;em&gt;steps&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;They are always executed at the end of the pipeline, after all steps execute.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Good! But how do we detect that steps and hooks exist? The answer is
&lt;a href=&quot;https://blog.appsignal.com/2021/09/07/an-introduction-to-metaprogramming-in-elixir.html&quot;&gt;metaprogramming&lt;/a&gt;! Luckily for us, Elixir has powerful metaprogramming
tools to make all this possible.&lt;/p&gt;
&lt;h2&gt;Setting Up the Required Macros in Elixir&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll need two things: &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/macros.html&quot;&gt;macros&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Module.html#module-compile-callbacks&quot;&gt;compile callbacks&lt;/a&gt; to read
information about the functions of a module, and store what a step and a hook are.&lt;/p&gt;
&lt;p&gt;Starting with the base module &lt;code&gt;Pipeline&lt;/code&gt;, we want to &lt;code&gt;use Pipeline&lt;/code&gt; in other modules. For that to happen, we
declare a special macro, &lt;code&gt;__using__/1&lt;/code&gt;. This macro is called with the keyword &lt;code&gt;use&lt;/code&gt; in Elixir.&lt;/p&gt;
&lt;p&gt;In this macro, we add a compile hook to the target module so that we can inject code into it. The &lt;code&gt;@before_compile&lt;/code&gt;
hook does exactly that by calling the given function when a compiler is about to generate the underlying bytecode. It
accepts either a module or a tuple with a module and function name. We&amp;#39;ll go with the second option to make things simpler.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Pipeline do
  defmacro __using__(_options) do
    quote do
      # Calls Pipeline.build_pipeline/1 before generating the final bytecode, allowing us to analyze, generate and
      # inject code whenever we call `use Pipeline`.
      @before_compile {Pipeline, :build_pipeline}
    end
  end

  defmacro build_pipeline(env) do
    # inject code!
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anything called inside the &lt;code&gt;quote&lt;/code&gt; block will be injected into the caller module — including the result of the
&lt;code&gt;@before_compile&lt;/code&gt; hook.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://elixir-lang.org/getting-started/meta/quote-and-unquote.html&quot;&gt;Check out the official docs for more information about &lt;code&gt;quote&lt;/code&gt; and &lt;code&gt;unquote&lt;/code&gt; blocks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, whenever we want to create a pipeline, we call &lt;code&gt;use&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyPipeline do
  use Pipeline # &amp;lt;- code will be injected!
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Detecting Steps and Hooks&lt;/h3&gt;
&lt;p&gt;We have everything in place to inject code, but we still need to generate the code that will be injected. Let&amp;#39;s expand
the &lt;code&gt;build_pipeline/1&lt;/code&gt; macro:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro build_pipeline(env) do
  # Fetch all public functions from the caller module
  definitions = Module.definitions_in(env.module, :def)

  # Filter functions that are steps and hooks
  steps = filter_functions(env.module, definitions, &amp;quot;_step&amp;quot;, 2)
  hooks = filter_functions(env.module, definitions, &amp;quot;_hook&amp;quot;, 2)

  # Generate code on the caller module
  quote do
    # returns all steps and hooks
    def __pipeline__, do: {unquote(steps), unquote(hooks)}

    # Syntatic sugar so we can execute directly from the module that defines it
    def execute(value, options \\ []), do: Pipeline.execute(__MODULE__, value, options)
  end

  # Filter functions from the given module based on their suffix and arity
  defp filter_functions(module, definitions, suffix, expected_arity) do
    functions =
      Enum.reduce(definitions, [], fn {function, arity}, acc -&amp;gt;
        # Detect if the function name ends with the desired suffix: _step or _hook
        valid_name? =
          function
          |&amp;gt; Atom.to_string()
          |&amp;gt; String.ends_with?(suffix)

        # Detect if the function arity matches the expected arity
        has_expected_args? = arity == expected_arity

        cond do
          valid_name? and has_expected_args? -&amp;gt;
            # In this case, the function does end with the desired suffix and has the correct arity.
            # We include it in the accumulator along with the line where it was declared so we can
            # order them by their position in their module
            {_, _, [line: line], _} = Module.get_definition(module, {function, arity})
            [{module, function, line} | acc]

          valid_name? -&amp;gt;
            # If the function has the desired suffix but the arity is not correct, we raise this error
            # because we don&amp;#39;t want people trying to figure out why their steps or hooks are not
            # being executed.
            raise(PipelineError, &amp;quot;Function #{function} does not accept #{expected_arity} parameters.&amp;quot;)

          true -&amp;gt;
            # If the function doesn&amp;#39;t match our filters, it&amp;#39;s not a part of the pipeline and can be
            # just ignored
            acc
        end
      end)

    # At this point we have filtered the functions that match the filter criteria but they
    # are not in order. We use the line number information to sort them and then drop it
    # once we don&amp;#39;t need it anymore.
    functions
    |&amp;gt; Enum.sort(fn {_, _, a}, {_, _, b} -&amp;gt; a &amp;lt;= b end) # order by line number
    |&amp;gt; Enum.map(fn {m, f, _l} -&amp;gt; {m, f} end)            # drop line number
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This macro receives the compiler &lt;code&gt;env&lt;/code&gt;, &lt;a href=&quot;https://hexdocs.pm/elixir/1.13.4/Macro.Env.html&quot;&gt;which has lots of context information&lt;/a&gt;. Here, the important bit is the &lt;em&gt;caller module&lt;/em&gt;,
accessible via the &lt;code&gt;env.module&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Then we use the &lt;a href=&quot;https://hexdocs.pm/elixir/1.13.0/Module.html#definitions_in/2&quot;&gt;module.definitions_in/2&lt;/a&gt; special
function to get a list of all functions declared on the module &lt;code&gt;env.module&lt;/code&gt; with the &lt;code&gt;def&lt;/code&gt; keyword.&lt;/p&gt;
&lt;p&gt;We call the
&lt;code&gt;Pipeline.filter_functions/4&lt;/code&gt; function to filter these definitions by their suffix and arity, essentially detecting our
steps and hooks! The &lt;code&gt;Pipeline.filter_functions/4&lt;/code&gt; function is kind of big, so I&amp;#39;ve added comments to help you
navigate through it.&lt;/p&gt;
&lt;p&gt;As said before, anything inside the &lt;code&gt;quote&lt;/code&gt; block is injected directly into the caller module. So whenever we call
&lt;code&gt;use Pipeline&lt;/code&gt;, the module will have two extra functions: &lt;code&gt;__pipeline__/0&lt;/code&gt;, and &lt;code&gt;execute/2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Pipeline&lt;/code&gt; module uses the first function to execute our custom pipeline, while the &lt;code&gt;execute/2&lt;/code&gt;
function is just a convenience function that will execute &lt;code&gt;Pipeline.execute/3&lt;/code&gt;. It allows us to execute our pipeline by
calling &lt;code&gt;MyPipeline.execute(value, options)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Speaking of &lt;code&gt;Pipeline.execute/3&lt;/code&gt;, it&amp;#39;s time to define it. This function is the core of this engine, and it&amp;#39;s responsible
for actually calling a reducer that will power our pipeline engine:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Pipeline do
  # ...

  def execute(module, value, options) do
    # Build a new initial state of the pipeline
    initial_state = State.new(value)

    # Fetch steps and hooks from the module
    {steps, hooks} = apply(module, :__pipeline__, [])

    # Run each step from the pipeline and build the final state
    final_state =
      Enum.reduce(steps, initial_state, fn reducer, current_state -&amp;gt;
        State.update(current_state, reducer, options)
      end)

    # Run each hook with the final state
    Enum.each(hooks, fn {module, function} -&amp;gt;
      apply(module, function, [final_state, options])
    end)

    # Transform the state value into an ok/error tuple
    case final_state do
      %State{valid?: true, value: value} -&amp;gt;
        {:ok, value}

      %State{errors: errors} -&amp;gt;
        {:error, errors}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/msramos/ex_pipeline/blob/f657556df3c48ed6fa33c9be892d8844a58cd654/lib/pipeline.ex&quot;&gt;Check out the complete version of this module here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In the complete version of this module, there is also another kind of hook, called an &lt;em&gt;async hook&lt;/em&gt;. Async hooks work
just like the hooks presented here, but are executed in parallel rather than sequentially. They will not be covered in
this post, since they are essentially a hook &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/Task.html&quot;&gt;executed with a Task&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Building and Executing a Pipeline&lt;/h3&gt;
&lt;p&gt;By simply calling &lt;code&gt;use Pipeline&lt;/code&gt; and writing function names with the &lt;code&gt;_step&lt;/code&gt; or &lt;code&gt;_hook&lt;/code&gt; suffix, we are now able to
build our pipelines. Let&amp;#39;s rewrite our last example from the first part of the post with this new mechanic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Checkout do
  use Pipeline

  def fetch_payment_information_step(value, options) do
    # ...
  end

  def fetch_user_step(value, options) do
    # ...
  end

  def fetch_address_step(value, options) do
    # ...
  end

  def create_order_step(value, options) do
    # ...
  end

  def report_checkout_attempt_hook(state, options) do
    # ...
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can execute this new pipeline like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;case Checkout.execute(%{params: params}, options) do
  {:ok, %{order: order}} -&amp;gt;
    conn
    |&amp;gt; put_flash(:info, &amp;quot;Order completed!&amp;quot;)
    |&amp;gt; redirect(to: Routes.order_path(conn, order))

  {:error, error}
    conn
    |&amp;gt; put_flash(:error, parse_error(error_description))
    |&amp;gt; render(&amp;quot;checkout.html&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No more &lt;code&gt;with&lt;/code&gt; blocks, and no need to manually handle errors. The controller is now focused on handling the HTTP layer, and
the checkout feature has an official place to live. Adding a new step to the checkout process just requires that we
write a function in the right place!&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this post, we learned how to express a set of transformations as a reducer. Then, using the power of macros, we automatically created pipelines by detecting the signature of functions at compile time.&lt;/p&gt;
&lt;p&gt;The features that use pipeline mechanics are explicit and contained — we know exactly what to expect and where to go
when modifying them. We expect all steps to look and behave in the same way. The basics of error handling are already in
place, you just need to decide what to do. These pipelines are, indeed, &lt;em&gt;predictable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I hope you&amp;#39;ve found this two-part series about keeping your Elixir code maintainable helpful. Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Write a Standalone CLI Application in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/08/09/write-a-standalone-cli-application-in-elixir.html"/>
    <id>https://blog.appsignal.com/2022/08/09/write-a-standalone-cli-application-in-elixir.html</id>
    <published>2022-08-09T00:00:00+00:00</published>
    <updated>2022-08-09T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how to write a command-line application in Elixir, using tools such as ElixirScript, OptionParser, Escript, Bakeware, and Burrito.</summary>
    <content type="html">&lt;p&gt;While Elixir is frequently associated with web development, this is not where its capabilities end. As a
general-purpose language, it can be used for virtually anything. You don&amp;#39;t have to take my word for it — projects such
as Nerves, Nx, Scenic, or LiveBook speak for themselves.&lt;/p&gt;
&lt;p&gt;But today, we will focus on something different:
writing a command-line application in Elixir and preparing it for distribution.&lt;/p&gt;
&lt;p&gt;Before we get going, let&amp;#39;s touch on why we&amp;#39;d write a CLI app and what we&amp;#39;ll cover in this tutorial.&lt;/p&gt;
&lt;h2&gt;Why Write a CLI App in Elixir?&lt;/h2&gt;
&lt;p&gt;CLI (command-line interface) applications have a wide variety of purposes. You probably already use some of
them often — think of &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;asdf&lt;/code&gt;, or even &lt;code&gt;mix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In our daily dev life, we usually write such applications to automate
things that are otherwise tedious — formatting code, preparing deployments, running backups, synchronizing
data, or... generating code. Yes, think about creating language-specific files from &lt;code&gt;.proto&lt;/code&gt; definitions. You probably
would use &lt;code&gt;protoc&lt;/code&gt; or &lt;code&gt;buf&lt;/code&gt; for that. Both of them are, in fact, CLI applications.&lt;/p&gt;
&lt;p&gt;In this tutorial, we are going to build something a lot simpler. Let&amp;#39;s set our requirements as follows: a script should
take a path to a directory as an argument. We will (non-recursively) get all the files from there and calculate their
mean size.&lt;/p&gt;
&lt;p&gt;During this journey, you will also learn about tools that will help you achieve your goal. This kind of endeavor
deserves a special name, so we will call it &lt;code&gt;MFSC&lt;/code&gt; — Mean File Size Calculator.&lt;/p&gt;
&lt;h2&gt;ElixirScript: Let&amp;#39;s Start Simple&lt;/h2&gt;
&lt;p&gt;Elixir already has a tool that is enough to get started. It&amp;#39;s called ElixirScript and is really simple to use:
you write code in a file with an &lt;code&gt;.exs&lt;/code&gt; extension, and then you run it with &lt;code&gt;elixir my_file.exs&lt;/code&gt;. I&amp;#39;m sure you have
seen some &lt;code&gt;.exs&lt;/code&gt; files before — for example, in Phoenix&amp;#39;s &lt;code&gt;config&lt;/code&gt; directory or in tests. These are examples of
ElixirScript.&lt;/p&gt;
&lt;p&gt;So, without further ado, let&amp;#39;s create the first version of our MFSC:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MFSC do
  def call do
    [directory] = System.argv()

    with true &amp;lt;- File.dir?(directory),
         {:ok, files} &amp;lt;- list_files(directory) do
      Enum.reduce(files, 0, fn file, size -&amp;gt; size + calculate_file_size(file) end)
      |&amp;gt; Kernel.div(length(files))
      |&amp;gt; IO.puts()
    end
  end

  defp list_files(directory) do
    case File.ls(directory) do
      {:ok, files} -&amp;gt;
        files =
          files
          |&amp;gt; Enum.map(&amp;amp;Path.join(directory, &amp;amp;1))
          |&amp;gt; Enum.reject(&amp;amp;File.dir?/1)

        {:ok, files}

      error -&amp;gt;
        error
    end
  end

  defp calculate_file_size(file) do
    file
    |&amp;gt; File.stat!()
    |&amp;gt; Map.get(:size)
  end
end

MFSC.call()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We define a module called, unsurprisingly, &lt;code&gt;MFSC&lt;/code&gt; with a &lt;code&gt;call/0&lt;/code&gt; function. This lists the files in the directory, then
iterates on them to find their size before finally calculating the average. The only piece relevant to a command-line script is this line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[directory] = System.argv()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;System.argv/0&lt;/code&gt; here returns a list of arguments passed to the script. We optimistically assume it&amp;#39;s always just one
argument and assign it to the &lt;code&gt;directory&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s it. If you run the script with an existing directory as an argument, it will return the mean length in bytes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;&amp;gt; elixir mfsc.exs ~/some_directory
1184
&amp;gt; elixir mfsc.exs ~/none_existing_dir
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, for an incorrect input (a directory that does not exist), it will just return nothing. Let&amp;#39;s fix
it by adding &lt;code&gt;else&lt;/code&gt; to the &lt;code&gt;with&lt;/code&gt; statement.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;with true &amp;lt;- File.dir?(directory),
     {:ok, files} &amp;lt;- list_files(directory) do
  Enum.reduce(files, 0, fn file, size -&amp;gt; size + calculate_file_size(file) end)
  |&amp;gt; Kernel.div(length(files))
  |&amp;gt; IO.puts()
else
  _ -&amp;gt;
    IO.puts(&amp;quot;Invalid input&amp;quot;)
    System.halt(1)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that I didn&amp;#39;t only add an error message but also a &lt;code&gt;System.halt(1)&lt;/code&gt; call. This is to return a non-zero
(i.e., non-success) exit code from a script (you can check the exit code of the last run command with &lt;code&gt;echo $?&lt;/code&gt;).
It is important to do so to be a &amp;#39;good CLI land citizen.&amp;#39;&lt;/p&gt;
&lt;p&gt;Why? Command-line applications often do not work on their own
but are chained together or called by other programs. An exit code helps to detect if a given part of a chain was run successfully (and we can expect the output to be in some predefined format) or not (in which case, we probably shouldn&amp;#39;t even try to parse output).&lt;/p&gt;
&lt;p&gt;We have a working script, except for one small issue. When you run it on an empty directory, it will crash because of
division by zero:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;** (ArithmeticError) bad argument in arithmetic expression: div(0, 0)
    :erlang.div(0, 0)
    mfsc.exs:8: MFSC.call/0
    (elixir 1.13.3) lib/code.ex:1183: Code.require_file/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s not nice. But what should we do on an empty directory? It&amp;#39;s not obvious. We could return zero. Or alternatively,
halt the application with a non-zero exit code.&lt;/p&gt;
&lt;p&gt;Or maybe — just a thought — we should leave the choice to the user?&lt;/p&gt;
&lt;h2&gt;OptionParser: More Robust Input Handling in Elixir&lt;/h2&gt;
&lt;p&gt;Remember how we assumed that there would always be only one input argument to our script? We&amp;#39;re about to ditch this
assumption. We want to introduce an option for the user to decide what should happen when an empty directory
is found.&lt;/p&gt;
&lt;p&gt;By default, we want to return an error, but there will be a flag to alter this behavior:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;&amp;gt; elixir mfsc.exs /my/empty/dir
Empty directory
&amp;gt; echo $?
10
&amp;gt; elixir mfsc.exs /my/empty/dir --allow-empty
0
&amp;gt; echo $?
0
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Fortunately, Elixir has a tool readily waiting for us in its standard library: &lt;code&gt;OptionParser&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s first play with it a bit in &lt;code&gt;iex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; OptionParser.parse([&amp;quot;/my/empty/dir&amp;quot;, &amp;quot;--allow-empty&amp;quot;], strict: [allow_empty: :boolean])
{[allow_empty: true], [&amp;quot;/my/empty/dir&amp;quot;], []}
iex(2)&amp;gt; OptionParser.parse([&amp;quot;/my/empty/dir&amp;quot;], strict: [allow_empty: :boolean])
{[], [&amp;quot;/my/empty/dir&amp;quot;], []}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first argument to the &lt;code&gt;OptionParser.parse/2&lt;/code&gt; function is a list of arguments that we normally get from
&lt;code&gt;System.argv/0&lt;/code&gt;. In this case, we are simulating it manually.&lt;/p&gt;
&lt;p&gt;The second one is the definition of our expected input.
It is a keyword list with three possible keys: &lt;code&gt;strict&lt;/code&gt;, &lt;code&gt;aliases&lt;/code&gt;, and &lt;code&gt;switches&lt;/code&gt;. For now, we will concentrate on &lt;code&gt;strict&lt;/code&gt;
as it is the basic one. In this example, we defined an expectation of one argument of the &lt;code&gt;boolean&lt;/code&gt; type.&lt;/p&gt;
&lt;p&gt;The return value is a tuple of three elements: the first is a list of parsed options, the second is for other (positional)
arguments, and the third one is for errors. Let&amp;#39;s see some more examples:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(3)&amp;gt; OptionParser.parse([&amp;quot;/my/empty/dir&amp;quot;, &amp;quot;/tmp/second/dir&amp;quot;], strict: [allow_empty: :boolean])
{[], [&amp;quot;/my/empty/dir&amp;quot;, &amp;quot;/tmp/second/dir&amp;quot;], []}
iex(4)&amp;gt; OptionParser.parse([&amp;quot;/my/empty/dir&amp;quot;, &amp;quot;--allow-empty=3&amp;quot;], strict: [allow_empty: :boolean])
{[], [&amp;quot;/my/empty/dir&amp;quot;], [{&amp;quot;--allow-empty&amp;quot;, &amp;quot;3&amp;quot;}]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the first example, we have two positional arguments and no parsed options. In the second, we violate
the constraint that &lt;code&gt;--allow-empty&lt;/code&gt; should be a boolean switch by passing the number 3 to it. As a result, it doesn&amp;#39;t
appear in parsed options but instead lands in errors.&lt;/p&gt;
&lt;p&gt;Knowing how &lt;code&gt;OptionParser&lt;/code&gt; works, we can add it to our app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MFSC do
  def call do
    parsed =
      System.argv()
      |&amp;gt; OptionParser.parse(strict: [allow_empty: :boolean])

    with {options, [directory], []} &amp;lt;- parsed,
         true &amp;lt;- File.dir?(directory),
         {:ok, files} &amp;lt;- list_files(directory) do
      Enum.reduce(files, 0, fn file, size -&amp;gt; size + calculate_file_size(file) end)
      |&amp;gt; print_size(files, options)
    else
      _ -&amp;gt;
        IO.puts(&amp;quot;Invalid input&amp;quot;)
        System.halt(1)
    end
  end

  defp print_size(0, _, options) do
    case Keyword.get(options, :allow_empty) do
      true -&amp;gt;
        IO.puts(&amp;quot;0&amp;quot;)

      _ -&amp;gt;
        IO.puts(&amp;quot;Empty directory&amp;quot;)
        System.halt(1)
    end
  end

  defp print_size(total_size, files, _) do
    IO.puts(div(total_size, length(files)))
  end

  # rest of the code does not change
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nice! We support our first input option.&lt;/p&gt;
&lt;p&gt;There is still a lot of work to do to make this app&amp;#39;s interface friendlier, but I&amp;#39;ll leave it up to you at this
point. Some ideas on what you could do include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Returning different error messages and exit codes for various errors (non-existing directory vs. empty directory
without &lt;code&gt;--allow-empty&lt;/code&gt; vs. some random access error)&lt;/li&gt;
&lt;li&gt;An option to print a result in a different format than just the number of bytes, for example:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;--output-format [B|K|M|smart]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Allowing recursive counting, i.e., also calculate file sizes in subdirectories and their subdirectories. Beware of
symbolic links leading to cycles!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Limitations of ElixirScript&lt;/h2&gt;
&lt;p&gt;So far, we&amp;#39;ve been using ElixirScript to create our CLI apps, but as our code grows, you will soon notice some
limitations in this approach.&lt;/p&gt;
&lt;p&gt;Splitting code into multiple files is inconvenient, and you cannot really use all
the awesome packages published at &lt;a href=&quot;https://hex.pm&quot;&gt;hex&lt;/a&gt;. You might overcome this by using &lt;code&gt;Mix.install/2&lt;/code&gt; inline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Mix.install([
  {:ecto_sql, &amp;quot;~&amp;gt; 3.8&amp;quot;}
])

# some code using Ecto
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is, however, one last problem: to run your application, people need to have Elixir installed on their computers.
This is what makes ElixirScript a nice tool to run something along an existing larger Elixir application (like tests
in a Phoenix project), but not for our use case.&lt;/p&gt;
&lt;p&gt;Elixir is still not a standard language. Some system repositories
might have really old versions of the language. Generally, the fewer dependencies the user needs to install themselves,
the more likely they will actually try out your application.&lt;/p&gt;
&lt;p&gt;How can we do better, then?&lt;/p&gt;
&lt;h2&gt;Using Escript for Your Elixir App&lt;/h2&gt;
&lt;p&gt;Escript is a built-in way to distribute whole Elixir applications as a single-file executable. This is, of course, one
level better than using ElixirScript. Let&amp;#39;s look closely at how to include it in our application.&lt;/p&gt;
&lt;p&gt;To use escript, we need to have a regular &lt;code&gt;mix&lt;/code&gt; project, not just a single file. But this is fine, as we want to split our
application into multiple files and use dependencies anyway. Let&amp;#39;s create a project then:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix new mfsc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a bunch of files in an &lt;code&gt;mfsc&lt;/code&gt; directory. Among them is &lt;code&gt;lib/mfsc.ex&lt;/code&gt;, where
we will put the code we built in the previous section.&lt;/p&gt;
&lt;p&gt;Theoretically, you should be able to run it via &lt;code&gt;mix run&lt;/code&gt; now,
but here&amp;#39;s an unpleasant surprise: &lt;code&gt;mix run&lt;/code&gt; resets &lt;code&gt;System.argv/0&lt;/code&gt;, and you&amp;#39;ll always get an empty array as the input. We are not
going to focus on hacking this. Instead, we will introduce escript right away.&lt;/p&gt;
&lt;p&gt;The first step: remove &lt;code&gt;MFSC.call()&lt;/code&gt; from the bottom of the file — we only want to define a module for now.&lt;/p&gt;
&lt;p&gt;Now we will add support for escript to our &lt;code&gt;mix.exs&lt;/code&gt; file. In the &lt;code&gt;project&lt;/code&gt; function that returns a keyword list of the
project configuration, add a relevant line for escript:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def project do
  [
    app: :mfsc,
    # bunch of other things
    escript: [main_module: MFSC]
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are almost there. Now we need to refactor the &lt;code&gt;call/0&lt;/code&gt; function to the &lt;code&gt;main/1&lt;/code&gt; function accepting one argument — &lt;code&gt;args&lt;/code&gt; — which will be the equivalent of &lt;code&gt;System.argv/0&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MFSC do
  def main(args) do
    parsed =
      args
      |&amp;gt; OptionParser.parse(strict: [allow_empty: :boolean])

# rest of the file remains unchanged
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s all, folks! We build the escript file with &lt;code&gt;mix escript.build&lt;/code&gt;. This will create an &lt;code&gt;mfsc&lt;/code&gt; executable file in the
project&amp;#39;s root directory. We can call it like a regular executable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;gt; mix escript.build
Generated escript mfsc with MIX_ENV=dev
&amp;gt; ./mfsc ~/empty_dir
Empty directory
&amp;gt; ./mfsc ~/empty_dir --allow-empty
0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a huge step forward from ElixirScript — and the user does not need to have Elixir installed on their
machine. Note, however, that they still need to have Erlang. On the other hand, this is a much more common dependency than
Elixir, and chances are they already have it. In the worst-case scenario, it&amp;#39;s just one thing less to install.&lt;/p&gt;
&lt;p&gt;If that&amp;#39;s not enough, we can improve things even further.&lt;/p&gt;
&lt;h2&gt;Bakeware and Burrito for Elixir&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/bake-bake-bake/bakeware&quot;&gt;Bakeware&lt;/a&gt; is a relatively new project (created in mid-2020) aiming to
create dependency-less executables from Elixir code. Let&amp;#39;s try it with MFSC. Bakeware leverages Elixir releases, so
we need to add support for them to &lt;code&gt;mix.exs&lt;/code&gt;. On top of that, we need the &lt;code&gt;bakeware&lt;/code&gt; dependency and to add our entry
module to &lt;code&gt;application&lt;/code&gt;. The complete &lt;code&gt;mix.exs&lt;/code&gt; should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Mfsc.MixProject do
  use Mix.Project

  def project do
    [
      app: :mfsc,
      version: &amp;quot;0.1.0&amp;quot;,
      elixir: &amp;quot;~&amp;gt; 1.13&amp;quot;,
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      escript: [main_module: MFSC],

      releases: [                          # here we define cli release
        cli: [
          steps: [:assemble, &amp;amp;Bakeware.assemble/1]
        ]
      ]
    ]
  end

  def application do
    [
      extra_applications: [:logger],
      mod: {MFSC, []}                      # adding our entry module
    ]
  end

  defp deps do
    [
      {:bakeware, &amp;quot;~&amp;gt; 0.2.4&amp;quot;}              # bakeware dependency
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, we need to adjust our &lt;code&gt;MFSC&lt;/code&gt; module by adding Bakeware scripting support:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MFSC do
  use Bakeware.Script

  @impl Bakeware.Script
  def main(args) do

# rest of the file
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that in place, we just need to run &lt;code&gt;mix release cli&lt;/code&gt;. This will take some time, but we end up with our standalone CLI application with
a &lt;code&gt;_build/dev/rel/bakeware/cli&lt;/code&gt; file. Let&amp;#39;s take it for a ride!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;&amp;gt; _build/dev/rel/bakeware/cli ~/empty_dir
Empty directory
&amp;gt; _build/dev/rel/bakeware/cli ~/empty_dir --allow-empty
0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This definitely looks familiar. However, you should know one thing — these files will only work on a similar operating
system as the one they were built on. For example, I created mine on Linux, and when I sent it to another Linux machine, it worked
without any issues. But it did not work on Intel Mac, not to mention M1 Mac.&lt;/p&gt;
&lt;p&gt;We might try to address this issue with an even newer project than Bakeware. It&amp;#39;s called
&lt;a href=&quot;https://github.com/burrito-elixir/burrito&quot;&gt;Burrito&lt;/a&gt; and the first public commit is just from October 2021. It
promises cross-platform standalone releases and is aimed at CLI applications. Burrito has a few additional dependencies,
namely &lt;code&gt;Zig&lt;/code&gt; and &lt;code&gt;xz&lt;/code&gt;. When we install them, we add another release to &lt;code&gt;mix.exs&lt;/code&gt; (remember to add the &lt;code&gt;burrito&lt;/code&gt; dependency too!):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;burrito_cli: [
  steps: [:assemble, &amp;amp;Burrito.wrap/1],
  burrito: [
    targets: [
      macos: [os: :darwin, cpu: :x86_64],
      macos_m1: [os: :darwin, cpu: :aarch64],
      linux: [os: :linux, cpu: :x86_64],
      windows: [os: :windows, cpu: :x86_64]
    ],
  ]
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, run the release process:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix release burrito_cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After a while, you should have the executables for different operating systems waiting under the &lt;code&gt;burrito_out&lt;/code&gt; directory,
for example, &lt;code&gt;burrito_out/burrito_cli_linux&lt;/code&gt;. Note that Burrito is still a work in progress, and you may experience some
bumps on the road. For me, at the time of writing this article, building for macOS from Linux did not work.&lt;/p&gt;
&lt;p&gt;If you want to learn more about Burrito, there&amp;#39;s a great talk by its author, Digit, from the EPEX conference. It&amp;#39;s called
&lt;em&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=oP9IQWaKciE&quot;&gt;Wrap your app in a BEAM burrito!&lt;/a&gt;&lt;/em&gt; In this talk, you&amp;#39;ll learn why the
project was born and the main hurdles along the way, followed by a live coding session.&lt;/p&gt;
&lt;h2&gt;The Downsides of Using Elixir for CLI Applications&lt;/h2&gt;
&lt;p&gt;Now that we&amp;#39;ve seen how easy it is to build a standalone CLI application in Elixir, let me warn you about one thing:
the startup time will be slow. In my tests, it always takes about half a second.&lt;/p&gt;
&lt;p&gt;This is not a problem for long-running
or interactive applications but might be a showstopper if you need a small tool to execute multiple times — for example, the &lt;code&gt;find&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;find . -maxdepth 1 -type f -exec ./my_elixir_app {} \;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The startup time of half a second is multiplied by the number of files, which may add up to quite significant delays.
You can experience this pain in the real world when you generate protobuf files for Elixir with
&lt;a href=&quot;https://github.com/elixir-protobuf/protobuf&quot;&gt;protobuf-elixir&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Should I Use Elixir for CLI Apps?&lt;/h2&gt;
&lt;p&gt;If some of the problems outlined in the previous sections of this post do not scare you or do not apply to your use case, by all means use
Elixir for CLI applications. It can be a lot of fun, especially combined with its concurrency abilities.&lt;/p&gt;
&lt;p&gt;I personally
did in my simple &lt;a href=&quot;https://github.com/katafrakt/locust&quot;&gt;stress-tester application&lt;/a&gt;, which
spawns multiple processes and attempts to flood a given URL with requests, gathering statistics on how it goes. And
I used it for work more than once, where a full-blown solution was not required.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;In this post, we built a simple CLI application using ElixirScript, learned to use &lt;code&gt;OptionParser&lt;/code&gt;, then released it using
&lt;code&gt;escript&lt;/code&gt; as an executable, which only requires Erlang to run.&lt;/p&gt;
&lt;p&gt;After that, we looked into creating more standalone
releases with Bakeware or Burrito. Finally, we explored some downsides of choosing Elixir for certain types of CLI
tools.&lt;/p&gt;
&lt;p&gt;I hope you found this a good starting point for writing a CLI app in Elixir.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Write a Functor in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/07/26/how-to-write-a-functor-in-elixir.html"/>
    <id>https://blog.appsignal.com/2022/07/26/how-to-write-a-functor-in-elixir.html</id>
    <published>2022-07-26T00:00:00+00:00</published>
    <updated>2022-07-26T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn all about functors and their benefits, then create a protocol for functors in Elixir.</summary>
    <content type="html">&lt;p&gt;There’s a function called &lt;code&gt;Enum.map&lt;/code&gt; in Elixir that works on multiple collection types, but it&amp;#39;s not without its issues.&lt;/p&gt;
&lt;p&gt;In this post, I will introduce you to a concept from functional programming called a functor. We’ll make a &lt;code&gt;Functor&lt;/code&gt; protocol with a function called &lt;code&gt;fmap&lt;/code&gt; that will aspire to be a better version of &lt;code&gt;Enum.map&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; The article is inspired by the Witchcraft library, which we covered in one of our &lt;a href=&quot;https://blog.appsignal.com/2022/02/08/functional-programming-in-elixir-with-witchcraft.html&quot;&gt;previous posts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But first: what&amp;#39;s the problem with &lt;code&gt;Enum.map&lt;/code&gt; exactly?&lt;/p&gt;
&lt;h2&gt;The Issue with &lt;code&gt;Enum.map&lt;/code&gt; in Elixir&lt;/h2&gt;
&lt;p&gt;While &lt;code&gt;Enum.map&lt;/code&gt; works fine with lists, its behavior is a bit odd for other collections.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; cities = %{&amp;quot;Latvia&amp;quot; =&amp;gt; &amp;quot;Riga&amp;quot;, &amp;quot;France&amp;quot; =&amp;gt; &amp;quot;Paris&amp;quot;, &amp;quot;Germany&amp;quot; =&amp;gt; Berlin}
%{&amp;quot;France&amp;quot; =&amp;gt; &amp;quot;Paris&amp;quot;, &amp;quot;Germany&amp;quot; =&amp;gt; Berlin, &amp;quot;Latvia&amp;quot; =&amp;gt; &amp;quot;Riga&amp;quot;}
iex(2)&amp;gt; cities = Enum.map(cities, fn x -&amp;gt; x end)
[{&amp;quot;France&amp;quot;, &amp;quot;Paris&amp;quot;}, {&amp;quot;Germany&amp;quot;, Berlin}, {&amp;quot;Latvia&amp;quot;, &amp;quot;Riga&amp;quot;}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even though we call it with an identity function that returns its input unchanged, we don’t get the same structure back.&lt;/p&gt;
&lt;p&gt;And we can’t use the result as a map.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(2)&amp;gt; Map.fetch(cities, &amp;quot;Latvia&amp;quot;)
** (BadMapError) expected a map, got: [{&amp;quot;France&amp;quot;, &amp;quot;Paris&amp;quot;}, {&amp;quot;Germany&amp;quot;, &amp;quot;Berlin&amp;quot;}, {&amp;quot;Latvia&amp;quot;, &amp;quot;Riga&amp;quot;}]
    (stdlib 3.17) :maps.find(&amp;quot;Latvia&amp;quot;, [{&amp;quot;France&amp;quot;, &amp;quot;Paris&amp;quot;}, {&amp;quot;Germany&amp;quot;, &amp;quot;Berlin&amp;quot;}, {&amp;quot;Latvia&amp;quot;, &amp;quot;Riga&amp;quot;}])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Understanding how &lt;code&gt;Enum.map&lt;/code&gt; works on maps depends on knowing two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Elixir thinks of maps as lists of tuples (but only when it wants to).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Enum.map&lt;/code&gt; will always return a list as a result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Safe to say, this is not intuitive. But what could be a better way to do things, and how can we ensure we don’t make the same mistake again?&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see how a functor can help.&lt;/p&gt;
&lt;h2&gt;What’s a Functor in Haskell?&lt;/h2&gt;
&lt;p&gt;In Haskell, &lt;code&gt;Functor&lt;/code&gt; is a &lt;a href=&quot;https://serokell.io/blog/haskell-typeclasses&quot;&gt;typeclass&lt;/a&gt;, an ‘interface’ with a set of methods common to multiple data types.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;-- Definition for illustrative purposes.

class Functor f where
  fmap :: (a -&amp;gt; b) -&amp;gt; f a -&amp;gt; f b
  (&amp;lt;$) :: a -&amp;gt; f b -&amp;gt; f a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The closest thing to typeclasses in Elixir is &lt;a href=&quot;https://blog.appsignal.com/2019/02/19/elixir-alchemy-pouring-protocols.html&quot;&gt;protocols&lt;/a&gt;. In the same way that we have &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/Enumerable.html&quot;&gt;&lt;code&gt;Enumerable&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;Enum&lt;/code&gt;) in Elixir, you can also think of &lt;code&gt;Functor&lt;/code&gt; as &lt;em&gt;Functor-able&lt;/em&gt;, or, in more human language, &lt;em&gt;Mappable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The important method of the Functor typeclass in Haskell is &lt;code&gt;fmap&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;fmap&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;fmap&lt;/code&gt; takes a function and a structure, then returns the same structure with the function applied to the structure&amp;#39;s content.&lt;/p&gt;
&lt;p&gt;In other words, it implements a &lt;strong&gt;structure-preserving transformation&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fmap&lt;/code&gt; is similar to &lt;code&gt;Enum.map&lt;/code&gt;, but there are some key differences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fmap&lt;/code&gt; returns the structure it is called on, while &lt;code&gt;Enum.map&lt;/code&gt; always returns a list.&lt;/li&gt;
&lt;li&gt;It enables you to map a wider set of structures. For example, in Haskell, you can use &lt;code&gt;fmap&lt;/code&gt; with single-item structures (like &lt;code&gt;{:ok, result}&lt;/code&gt;) and even functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; In Haskell, &lt;code&gt;fmap&lt;/code&gt; takes the function as the first argument. But since Elixir usually has data in the first position due to pipes, I&amp;#39;ve switched the arguments while adapting the concept.&lt;/p&gt;
&lt;p&gt;It’s best to look at some examples to understand what &lt;code&gt;fmap&lt;/code&gt; does. The examples below use the implementation that we will later create ourselves.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; import Functor
Functor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Lists&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(2)&amp;gt; fmap([1, 2, 3], fn x -&amp;gt; x + 1 end)
[2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Maps&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(3)&amp;gt; cities = %{&amp;quot;Latvia&amp;quot; =&amp;gt; &amp;quot;riga&amp;quot;, &amp;quot;France&amp;quot; =&amp;gt; &amp;quot;paris&amp;quot;, &amp;quot;Germany&amp;quot; =&amp;gt; &amp;quot;berlin&amp;quot;}
%{&amp;quot;France&amp;quot; =&amp;gt; &amp;quot;paris&amp;quot;, &amp;quot;Germany&amp;quot; =&amp;gt; &amp;quot;berlin&amp;quot;, &amp;quot;Latvia&amp;quot; =&amp;gt; &amp;quot;riga&amp;quot;}
iex(4)&amp;gt; fmap(cities, fn x -&amp;gt; String.capitalize(x) end)
%{&amp;quot;France&amp;quot; =&amp;gt; &amp;quot;Paris&amp;quot;, &amp;quot;Germany&amp;quot; =&amp;gt; &amp;quot;Berlin&amp;quot;, &amp;quot;Latvia&amp;quot; =&amp;gt; &amp;quot;Riga&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Trees&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(5)&amp;gt; a = %Tree{value: 1, children: [%Tree{value: 2, children: []}, %Tree{value: 3, children: []}]}
%Tree{
  children: [%Tree{children: [], value: 2}, %Tree{children: [], value: 3}],
  value: 1
}
iex(6)&amp;gt; fmap(a, fn x -&amp;gt; x + 1 end)
%Tree{
  children: [%Tree{children: [], value: 3}, %Tree{children: [], value: 4}],
  value: 2
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Result tuples&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(7)&amp;gt; fmap({:ok, 4}, fn x -&amp;gt; x + 3 end)
{:ok, 7}
iex(8)&amp;gt; fmap({:error, :not_a_number}, fn x -&amp;gt; x + 3 end)
{:error, :not_a_number}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you look at these examples, you’ll see that they all have a/some value(s) wrapped in a structure. &lt;code&gt;fmap&lt;/code&gt; uses the function we provide to change the value(s) while keeping the structure the same.&lt;/p&gt;
&lt;p&gt;If I could write its typespec, it would look something like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@spec fmap(f(a), (a -&amp;gt; b)) :: f(b)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It takes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;something of type &lt;code&gt;a&lt;/code&gt; wrapped in type &lt;code&gt;f&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a function from type &lt;code&gt;a&lt;/code&gt; to type &lt;code&gt;b&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And it returns a value of type &lt;code&gt;b&lt;/code&gt; wrapped in type &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Functor Laws in Elixir&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;fmap&lt;/code&gt; needs to follow a set of equational laws to achieve its goal. And if laws scare you — please skip this, look at the implementation, then come back, and it will be easier.&lt;/p&gt;
&lt;p&gt;In Haskell, the compiler doesn&amp;#39;t check these laws by default, but you need to follow them for the implementation to ‘make sense’.&lt;/p&gt;
&lt;p&gt;The first law says that if you have a function that returns its output untouched, ‘fmapping’ it will do the same.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;fmap(y, fn x -&amp;gt; x end) == y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second law says that composing two ‘fmaps’ is the same as ‘fmapping’ the composition of those functions.&lt;/p&gt;
&lt;p&gt;It looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;(fmap(x, f1) |&amp;gt; fmap (f2)) == (fmap(x, fn y -&amp;gt; f2(f1(y)) end))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The laws are awkward to express in Elixir, but they basically work to preserve the structure of the type you’re mapping over.&lt;/p&gt;
&lt;p&gt;The implementation of &lt;code&gt;Enum.map&lt;/code&gt; for maps, for example, satisfies the second law, but doesn’t satisfy the first. Hence, it is not a lawful implementation of &lt;code&gt;fmap&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Why Do You Need to Know About Functors?&lt;/h2&gt;
&lt;p&gt;In programming, some patterns repeat themselves time and time again.&lt;/p&gt;
&lt;p&gt;For a long time, people have been trying to describe these patterns and pass them on to other software developers to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Solve problems faster&lt;/li&gt;
&lt;li&gt;Expand ‘tools for thought’&lt;/li&gt;
&lt;li&gt;Make communication easier.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A functor is also a pattern, just like singleton and factory.&lt;/p&gt;
&lt;p&gt;Most classic patterns are useful, yet appear infrequently. But patterns like functors (and other math-based typeclasses) are so simple in their internal structure that they are bound to appear in your code (even if you don&amp;#39;t mean them to). At that point, you can either use the knowledge we have to handle them or not.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at an example. In Elixir, a lot of our code is expressed in pipelines, which can be looked at as a series of transformations on data. It&amp;#39;s very readable: one of the main reasons why the syntax of Elixir is so attractive.&lt;/p&gt;
&lt;p&gt;Functors can help us make our code even better in two ways.&lt;/p&gt;
&lt;p&gt;First, functors express pipe-able transformations of collections of data. If we have a &lt;code&gt;fmap&lt;/code&gt; function that returns the same kind of wrapper, we can easily pipe transforms into each other without calling &lt;code&gt;Enum.into()&lt;/code&gt; in between.&lt;/p&gt;
&lt;p&gt;Secondly, functors also help to transform nested values in pipelines. If a function returns a data type with a more complex structure like &lt;code&gt;{:ok, result}/{:error, error}&lt;/code&gt;, we sometimes run into problems when piping. To handle the value, we either need to deconstruct it or write a function that handles the structure and does the transformation behind the scenes.&lt;/p&gt;
&lt;p&gt;The first can create such horrors as piping into case statements in the middle of a pipeline, while the second can introduce a lot of code duplication and make code more obscure.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fmap&lt;/code&gt; enables us to apply a function to a nested value without explicitly destructuring, unwrapping, and/or repacking the data. The word &lt;code&gt;fmap&lt;/code&gt; informs other readers of your code what the function does. Then, after all transformations are complete, you can handle the resulting value.&lt;/p&gt;
&lt;p&gt;Now that we have a feel for what functors are, we can try to replicate their behavior in Elixir. To do that, we’ll use protocols.&lt;/p&gt;
&lt;h2&gt;Simulating Functors in Elixir&lt;/h2&gt;
&lt;p&gt;In this section, we will create a &lt;a href=&quot;https://hexdocs.pm/elixir/1.12.3/Protocol.html&quot;&gt;protocol&lt;/a&gt; for functors and provide implementations for four data types: lists, maps, trees, and result tuples.&lt;/p&gt;
&lt;h3&gt;Set-up&lt;/h3&gt;
&lt;p&gt;For this tutorial, we will need a new Elixir project.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix new functor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a file called &lt;code&gt;functor.ex&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Create a &lt;code&gt;Functor&lt;/code&gt; Protocol&lt;/h3&gt;
&lt;p&gt;This is rather straightforward.&lt;/p&gt;
&lt;p&gt;First we open &lt;code&gt;functor.ex&lt;/code&gt;. Then we use the &lt;code&gt;defprotocol&lt;/code&gt; macro to create a protocol.&lt;/p&gt;
&lt;p&gt;We provide the functions that the protocol will have to the macro. In our case, the only function is &lt;code&gt;fmap&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defprotocol Functor do
  def fmap(a, f)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s all we need to do.&lt;/p&gt;
&lt;h3&gt;Create an Implementation for Lists&lt;/h3&gt;
&lt;p&gt;Of course, a protocol is only as good as its implementations.&lt;/p&gt;
&lt;p&gt;We can create new implementations for a protocol with the &lt;code&gt;defimpl&lt;/code&gt; macro. Let’s do the list right inside &lt;code&gt;functor.ex&lt;/code&gt; since list is a staple data type.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fmap&lt;/code&gt; for lists is the same as a regular map. So we’ll just use &lt;code&gt;:lists.map&lt;/code&gt; from grandpa Erlang for the implementation.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defimpl Functor, for: List do
  @spec fmap(list, (list -&amp;gt; list)) :: list
  def fmap(a, f), do: :lists.map(f, a)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s how &lt;code&gt;fmap&lt;/code&gt; works for lists:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; Functor.fmap([1,2,3], fn x -&amp;gt; x + 1 end)
[2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create an Implementation for Maps&lt;/h3&gt;
&lt;p&gt;Now we’ve come to the data type we mentioned at the start of the article.&lt;/p&gt;
&lt;p&gt;The easiest way to make &lt;code&gt;Enum.map()&lt;/code&gt; return a map is to pack it back into a map after mapping it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defimpl Functor, for: Map do
  def fmap(a, f), do: Enum.map(a, f) |&amp;gt; Enum.into(%{})
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But there’s a small problem here. It can easily fail.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; Functor.fmap(%{Netherlands: &amp;quot;Amsterdam&amp;quot;}, fn {k, v} -&amp;gt; v end)
** (ArgumentError) argument error
    (stdlib 3.17) :maps.from_list([&amp;quot;Amsterdam&amp;quot;])
    (elixir 1.13.0) lib/enum.ex:1448: Enum.into_map/1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is one of the reasons why &lt;code&gt;Enum.map()&lt;/code&gt; on maps returns lists. The function you provide might create something that isn&amp;#39;t a map anymore.&lt;/p&gt;
&lt;p&gt;It’s also not a valid functor implementation. Functors can change only one value: they can map either keys or values, and we have to choose one for the implementation.&lt;/p&gt;
&lt;p&gt;We can solve both of these problems at the same time by limiting the mapping operation to the values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defimpl Functor, for: Map do
  def fmap(a, f) do
    map_in_list = Map.to_list(a)

    :lists.map(fn {k, v} -&amp;gt; {k, f.(v)} end, map_in_list)
    |&amp;gt; Enum.into(%{})
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s how it works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; Functor.fmap(%{Netherlands: &amp;quot;Amsterdam&amp;quot;}, fn x -&amp;gt; x &amp;lt;&amp;gt; &amp;quot;!&amp;quot; end)
%{Netherlands: &amp;quot;Amsterdam!&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are some arguments against this implementation (even though it is a valid functor 😅). Having a map function work only on values might be as unintuitive as having it return a list.&lt;/p&gt;
&lt;p&gt;You also can&amp;#39;t work with the keys in any capacity — you need other functions for that. But every time you call &lt;code&gt;fmap&lt;/code&gt; on a map, you will get a map back.&lt;/p&gt;
&lt;h3&gt;Create an Implementation for Trees&lt;/h3&gt;
&lt;p&gt;Now that we have seen how to define fmap for simpler data types, let&amp;#39;s try to define it for a type not served by the &lt;code&gt;Enum&lt;/code&gt; protocol — trees.&lt;/p&gt;
&lt;p&gt;First off, we need to define the struct. We’ll do that in &lt;code&gt;structures.ex&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Tree do
  defstruct value: nil, children: []

  @type t() :: %__MODULE__{
          value: any(),
          children: [t()]
        }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For simplicity’s sake, each of the tree&amp;#39;s nodes has a value and a list of children that can be empty.&lt;/p&gt;
&lt;p&gt;Now we can define the Functor implementation inside the module. In the definition, we can skip the &lt;code&gt;for: Tree&lt;/code&gt; part — Elixir will know we mean the module struct.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Tree do
  # ...
  defimpl Functor do

  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All that is left is to write the implementation, which will be recursive.&lt;/p&gt;
&lt;p&gt;We’ll apply the function to the value if we have a leaf (which has no children).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def fmap(%Tree{value: value, children: []}, f), do: %Tree{value: f.(value), children: []}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the node has children, we need to &lt;em&gt;map this fmap&lt;/em&gt; over all of them. This gives us a great opportunity to use the &lt;code&gt;Functor.fmap&lt;/code&gt; we created earlier!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def fmap(%Tree{value: value, children: children}, f) do
  updated_children = Functor.fmap(children, fn x -&amp;gt; fmap(x, f) end)
  %Tree{value: f.(value), children: updated_children}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you understand the piece of code above, you have already achieved a certain level of enlightenment about functors ☯&lt;/p&gt;
&lt;p&gt;Here’s how the function works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; a = %Tree{value: 1, children: [%Tree{value: 2, children: []}, %Tree{value: 3, children: []}]}
%Tree{
  children: [%Tree{children: [], value: 2}, %Tree{children: [], value: 3}],
  value: 1
}
iex(2)&amp;gt; Functor.fmap(a, fn x -&amp;gt; x + 1 end)
%Tree{
  children: [%Tree{children: [], value: 3}, %Tree{children: [], value: 4}],
  value: 2
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As an exercise, you can try to create a struct for a &lt;em&gt;binary tree&lt;/em&gt; — one where a node has a maximum of two children — and a &lt;code&gt;fmap&lt;/code&gt; implementation for this struct.&lt;/p&gt;
&lt;h3&gt;Create an Implementation for Result Tuples&lt;/h3&gt;
&lt;p&gt;Finally, let&amp;#39;s see how we can implement &lt;code&gt;fmap&lt;/code&gt; for result tuples.&lt;/p&gt;
&lt;p&gt;Now, mapping a tuple might seem counterintuitive for some. But transforming a collection of values is not the only thing &lt;code&gt;fmap&lt;/code&gt; can do. Another angle of how we can look at &lt;code&gt;fmap&lt;/code&gt; is that it &lt;em&gt;lifts&lt;/em&gt; a function into a context.&lt;/p&gt;
&lt;p&gt;In Elixir, functions sometimes return one of &lt;code&gt;{:ok, result}&lt;/code&gt; or &lt;code&gt;{:error, error}&lt;/code&gt;. We can call this the context of a computation that might have succeeded or failed.&lt;/p&gt;
&lt;p&gt;Now imagine we want to apply a function such as &lt;code&gt;fn x -&amp;gt; x + 1 end&lt;/code&gt; to this result.&lt;/p&gt;
&lt;p&gt;We can either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unpack it via pattern-matching and handle the error right here, right now.&lt;/li&gt;
&lt;li&gt;Lift the function inside the context of possible error and then send the result somewhere further.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is pretty straightforward to do the second with this tuple. If we have an &lt;code&gt;{:ok, result}&lt;/code&gt;, we just apply the function to the result. If we have an &lt;code&gt;{:error, error}&lt;/code&gt;, we don’t apply the function, but simply pass on the error.&lt;/p&gt;
&lt;p&gt;But there are some problems with making a functor implementation.&lt;/p&gt;
&lt;p&gt;To do it, we have to dispatch on the &lt;code&gt;Tuple&lt;/code&gt; type, which theoretically has a lawful Functor implementation of its own that changes only the last element of the tuple.&lt;/p&gt;
&lt;p&gt;Since Elixir cannot discern our intentions, this would mean doing something practical yet a bit unlawful.&lt;/p&gt;
&lt;p&gt;But since “practical yet a bit unlawful” sounds like the best characterization of Elixir I’ve read, we’ll go ahead and do it anyway.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defimpl Functor, for: Tuple do
  def fmap({:ok, result}, f), do: {:ok, f.(result)}
  def fmap({:error, reason}, \_f), do: {:error, reason}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s how it works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(2)&amp;gt; fmap({:ok, 4}, fn x -&amp;gt; x + 3 end)
{:ok, 7}
iex(3)&amp;gt; fmap({:error, :not_a_number}, fn x -&amp;gt; x + 3 end)
{:error, :not_a_number}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lawful but unidiomatic way to do this in Elixir would be to create two structs — &lt;code&gt;%Result.Ok{}&lt;/code&gt; and &lt;code&gt;%Result.Err{}&lt;/code&gt; — and define the &lt;code&gt;fmap&lt;/code&gt; implementation for those instead.
As an exercise, you can try to do this on your own.&lt;/p&gt;
&lt;h2&gt;Are Functors Useful in Elixir?&lt;/h2&gt;
&lt;p&gt;Now that we have created a basic yet working protocol for functors, it’s good to ask: is this thing useful?&lt;/p&gt;
&lt;p&gt;Well, it&amp;#39;s kind of cute. We can use it to do some cool things, such as create a map function that works on both a list of trees and a tree of lists.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def mega_map(a, f) do
  Functor.fmap(a, fn x -&amp;gt; Functor.fmap(x, f) end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And when we add a couple more implementations, having a mapping function that works on multiple data types (like &lt;code&gt;Enum.map&lt;/code&gt;) but doesn&amp;#39;t always return list can be handy.&lt;/p&gt;
&lt;p&gt;But the power of Haskell-inspired ideas is proportional to the infrastructure you have to work with them. Let&amp;#39;s think of this as an optimization exercise. We’re traveling away from a local idiomatic Elixir peak to write code that is more expressive and intuitive.&lt;/p&gt;
&lt;p&gt;In Haskell, you have access to a ton of other ‘mathy’ typeclasses like Applicative, Monad, and more to help you write code that’s starkly different from Elixir. And it’s much easier because of the type system and other peripherals.&lt;/p&gt;
&lt;p&gt;At the same time, what happens if we carefully pick out concepts from other programming languages and adapt them to how we write Elixir right now? We develop a way of writing Elixir that is more convenient and makes sense to adopters from other functional programming languages.&lt;/p&gt;
&lt;p&gt;This is akin to mainstream languages borrowing higher-order functions and result types from functional programming. Haskell&amp;#39;s whole complex type machinery is not needed in Elixir, but perhaps there is a simpler way to structure work with collections that doesn’t take inspiration from Ruby.&lt;/p&gt;
&lt;p&gt;In particular, I&amp;#39;ve lately fallen in love with Witchcraft&amp;#39;s vision for how the syntax of Elixir could look. It provides custom operators that work in a pipe-like fashion. For example, you can use &lt;code&gt;~&amp;gt;&lt;/code&gt; instead of &lt;code&gt;|&amp;gt; fmap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Having a few custom operators like these that synergize with how idiomatic Elixir is written, yet follow strict laws for implementation, would enable writing very expressive code that still feels like Elixir.&lt;/p&gt;
&lt;p&gt;And given the news that Elixir is working on a &lt;a href=&quot;https://twitter.com/josevalim/status/1535008937640181760?s=20&amp;t=g8IJbaJyi5TZuDdbgDmLqg&quot;&gt;set-theoretic type system&lt;/a&gt;, it’s high time to take a quick peek in the direction of other typed functional languages.&lt;/p&gt;
&lt;h2&gt;Wrap Up and Further Learning&lt;/h2&gt;
&lt;p&gt;In this article, we covered how to build a simple protocol for functors, together with implementations for four data types: lists, maps, trees, and result tuples.&lt;/p&gt;
&lt;p&gt;If you’re interested in trying out more functors magic in Elixir, check out &lt;a href=&quot;https://github.com/witchcrafters/witchcraft&quot;&gt;Witchcraft&lt;/a&gt;, which has been my main inspiration for this post.&lt;/p&gt;
&lt;p&gt;And if you want to delve deeper into the world of typed functional programming, you should definitely try out Haskell. The best way to do that is to start with one of these books: &lt;em&gt;&lt;a href=&quot;https://haskellbook.com/&quot;&gt;Haskell Programming From First Principles&lt;/a&gt;&lt;/em&gt; or &lt;em&gt;&lt;a href=&quot;https://www.manning.com/books/get-programming-with-haskell&quot;&gt;Get Programming With Haskell&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Writing Predictable Elixir Code with Reducers</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/07/19/writing-predictable-elixir-code-with-reducers.html"/>
    <id>https://blog.appsignal.com/2022/07/19/writing-predictable-elixir-code-with-reducers.html</id>
    <published>2022-07-19T00:00:00+00:00</published>
    <updated>2022-07-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first part of this two-part series, find out what code predictability is and how to apply it to your Elixir code.</summary>
    <content type="html">&lt;p&gt;This is the first part of a two-part series about maintainable code in Elixir. In this part, we will show how code predictability plays a crucial role in a project&amp;#39;s short and long-term health. We will use Elixir&amp;#39;s built-in features for this, like the pipe operator, tuples, and &lt;code&gt;with&lt;/code&gt;
blocks.&lt;/p&gt;
&lt;p&gt;First, we&amp;#39;ll explain what predictability is and why it is so important. Then we will go through some tools that Elixir
already has and how you can use them to write better code.&lt;/p&gt;
&lt;p&gt;Finally, we&amp;#39;ll demonstrate how some simple rules can help developers write code that is easy to read, write, and
maintain.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;On Complexity and Predictability&lt;/h2&gt;
&lt;p&gt;I still remember when I first started learning about functions in my math class. Things seemed simple and easy to understand:&lt;/p&gt;
&lt;p&gt;$$
L = \frac{1}{2} \rho v^2 S C_L
$$&lt;/p&gt;
&lt;p&gt;$$
y(x) = 2x
$$&lt;/p&gt;
&lt;p&gt;One function, one variable, and one simple operation.&lt;/p&gt;
&lt;p&gt;But as the years passed and more complex things were added to the basics, the small and easy functions were gone.
I was reading stuff like this:&lt;/p&gt;
&lt;div className=&quot;math math-display&quot;&gt;
  &lt;span className=&quot;katex-display&quot;&gt;
    &lt;span className=&quot;katex&quot;&gt;
      &lt;span className=&quot;katex-mathml&quot;&gt;
        &lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;
          &lt;semantics&gt;
            &lt;mrow&gt;
              &lt;mi&gt;f&lt;/mi&gt;
              &lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;
              &lt;mi&gt;x&lt;/mi&gt;
              &lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;
              &lt;mi&gt;y&lt;/mi&gt;
              &lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;
              &lt;mo&gt;=&lt;/mo&gt;
              &lt;mfrac&gt;
                &lt;mrow&gt;
                  &lt;mi&gt;α&lt;/mi&gt;
                  &lt;mi&gt;log&lt;/mi&gt;
                  &lt;mo&gt;⁡&lt;/mo&gt;
                  &lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;
                  &lt;mfrac&gt;
                    &lt;msup&gt;
                      &lt;mi&gt;x&lt;/mi&gt;
                      &lt;mn&gt;2&lt;/mn&gt;
                    &lt;/msup&gt;
                    &lt;msup&gt;
                      &lt;mi&gt;y&lt;/mi&gt;
                      &lt;mn&gt;3&lt;/mn&gt;
                    &lt;/msup&gt;
                  &lt;/mfrac&gt;
                  &lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;
                &lt;/mrow&gt;
                &lt;mover accent=&quot;true&quot;&gt;
                  &lt;mi&gt;θ&lt;/mi&gt;
                  &lt;mo&gt;˘&lt;/mo&gt;
                &lt;/mover&gt;
              &lt;/mfrac&gt;
            &lt;/mrow&gt;
            &lt;annotation encoding=&quot;application/x-tex&quot;&gt;Formula&lt;/annotation&gt;
          &lt;/semantics&gt;
        &lt;/math&gt;
      &lt;/span&gt;
      &lt;span className=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;
        &lt;span className=&quot;base&quot;&gt;
          &lt;span
            className=&quot;strut&quot;
            style={{ height: &quot;1em&quot;, verticalAlign: &quot;-0.25em&quot; }}
          &gt;&lt;/span&gt;
          &lt;span
            className=&quot;mord mathnormal&quot;
            style={{ marginRight: &quot;0.10764em&quot; }}
          &gt;
            f
          &lt;/span&gt;
          &lt;span className=&quot;mopen&quot;&gt;(&lt;/span&gt;
          &lt;span className=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;
          &lt;span className=&quot;mpunct&quot;&gt;,&lt;/span&gt;
          &lt;span className=&quot;mspace&quot; style={{ marginRight: &quot;0.1667em&quot; }}&gt;&lt;/span&gt;
          &lt;span
            className=&quot;mord mathnormal&quot;
            style={{ marginRight: &quot;0.03588em&quot; }}
          &gt;
            y
          &lt;/span&gt;
          &lt;span className=&quot;mclose&quot;&gt;)&lt;/span&gt;
          &lt;span className=&quot;mspace&quot; style={{ marginRight: &quot;0.2778em&quot; }}&gt;&lt;/span&gt;
          &lt;span className=&quot;mrel&quot;&gt;=&lt;/span&gt;
          &lt;span className=&quot;mspace&quot; style={{ marginRight: &quot;0.2778em&quot; }}&gt;&lt;/span&gt;
        &lt;/span&gt;
        &lt;span className=&quot;base&quot;&gt;
          &lt;span
            className=&quot;strut&quot;
            style={{ height: &quot;2.7369em&quot;, verticalAlign: &quot;-0.8479em&quot; }}
          &gt;&lt;/span&gt;
          &lt;span className=&quot;mord&quot;&gt;
            &lt;span className=&quot;mord&quot;&gt;
              &lt;span className=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;
              &lt;span className=&quot;mfrac&quot;&gt;
                &lt;span className=&quot;vlist-t vlist-t2&quot;&gt;
                  &lt;span className=&quot;vlist-r&quot;&gt;
                    &lt;span className=&quot;vlist&quot; style={{ height: &quot;1.889em&quot; }}&gt;
                      &lt;span style={{ top: &quot;-2.17em&quot; }}&gt;
                        &lt;span
                          className=&quot;pstrut&quot;
                          style={{ height: &quot;3.0179em&quot; }}
                        &gt;&lt;/span&gt;
                        &lt;span className=&quot;mord&quot;&gt;
                          &lt;span className=&quot;mord accent&quot;&gt;
                            &lt;span className=&quot;vlist-t&quot;&gt;
                              &lt;span className=&quot;vlist-r&quot;&gt;
                                &lt;span
                                  className=&quot;vlist&quot;
                                  style={{ height: &quot;0.9579em&quot; }}
                                &gt;
                                  &lt;span style={{ top: &quot;-3em&quot; }}&gt;
                                    &lt;span
                                      className=&quot;pstrut&quot;
                                      style={{ height: &quot;3em&quot; }}
                                    &gt;&lt;/span&gt;
                                    &lt;span
                                      className=&quot;mord mathnormal&quot;
                                      style={{ marginRight: &quot;0.02778em&quot; }}
                                    &gt;
                                      θ
                                    &lt;/span&gt;
                                  &lt;/span&gt;
                                  &lt;span style={{ top: &quot;-3.2634em&quot; }}&gt;
                                    &lt;span
                                      className=&quot;pstrut&quot;
                                      style={{ height: &quot;3em&quot; }}
                                    &gt;&lt;/span&gt;
                                    &lt;span
                                      className=&quot;accent-body&quot;
                                      style={{ left: &quot;-0.1667em&quot; }}
                                    &gt;
                                      &lt;span className=&quot;mord&quot;&gt;˘&lt;/span&gt;
                                    &lt;/span&gt;
                                  &lt;/span&gt;
                                &lt;/span&gt;
                              &lt;/span&gt;
                            &lt;/span&gt;
                          &lt;/span&gt;
                        &lt;/span&gt;
                      &lt;/span&gt;
                      &lt;span style={{ top: &quot;-3.2479em&quot; }}&gt;
                        &lt;span
                          className=&quot;pstrut&quot;
                          style={{ height: &quot;3.0179em&quot; }}
                        &gt;&lt;/span&gt;
                        &lt;span
                          className=&quot;frac-line&quot;
                          style={{ borderBottomWidth: &quot;0.04em&quot; }}
                        &gt;&lt;/span&gt;
                      &lt;/span&gt;
                      &lt;span style={{ top: &quot;-3.889em&quot; }}&gt;
                        &lt;span
                          className=&quot;pstrut&quot;
                          style={{ height: &quot;3.0179em&quot; }}
                        &gt;&lt;/span&gt;
                        &lt;span className=&quot;mord&quot;&gt;
                          &lt;span
                            className=&quot;mord mathnormal&quot;
                            style={{ marginRight: &quot;0.0037em&quot; }}
                          &gt;
                            α
                          &lt;/span&gt;
                          &lt;span
                            className=&quot;mspace&quot;
                            style={{ marginRight: &quot;0.1667em&quot; }}
                          &gt;&lt;/span&gt;
                          &lt;span className=&quot;mop&quot;&gt;
                            lo
                            &lt;span style={{ marginRight: &quot;0.01389em&quot; }}&gt;g&lt;/span&gt;
                          &lt;/span&gt;
                          &lt;span className=&quot;mopen&quot;&gt;(&lt;/span&gt;
                          &lt;span className=&quot;mord&quot;&gt;
                            &lt;span className=&quot;mord&quot;&gt;
                              &lt;span className=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;
                              &lt;span className=&quot;mfrac&quot;&gt;
                                &lt;span className=&quot;vlist-t vlist-t2&quot;&gt;
                                  &lt;span className=&quot;vlist-r&quot;&gt;
                                    &lt;span
                                      className=&quot;vlist&quot;
                                      style={{ height: &quot;1.0179em&quot; }}
                                    &gt;
                                      &lt;span style={{ top: &quot;-2.655em&quot; }}&gt;
                                        &lt;span
                                          className=&quot;pstrut&quot;
                                          style={{ height: &quot;3em&quot; }}
                                        &gt;&lt;/span&gt;
                                        &lt;span className=&quot;sizing reset-size6 size3 mtight&quot;&gt;
                                          &lt;span className=&quot;mord mtight&quot;&gt;
                                            &lt;span className=&quot;mord mtight&quot;&gt;
                                              &lt;span
                                                className=&quot;mord mathnormal mtight&quot;
                                                style={{
                                                  marginRight: &quot;0.03588em&quot;,
                                                }}
                                              &gt;
                                                y
                                              &lt;/span&gt;
                                              &lt;span className=&quot;msupsub&quot;&gt;
                                                &lt;span className=&quot;vlist-t&quot;&gt;
                                                  &lt;span className=&quot;vlist-r&quot;&gt;
                                                    &lt;span
                                                      className=&quot;vlist&quot;
                                                      style={{
                                                        height: &quot;0.7463em&quot;,
                                                      }}
                                                    &gt;
                                                      &lt;span
                                                        style={{
                                                          top: &quot;-2.786em&quot;,
                                                          marginRight:
                                                            &quot;0.0714em&quot;,
                                                        }}
                                                      &gt;
                                                        &lt;span
                                                          className=&quot;pstrut&quot;
                                                          style={{
                                                            height: &quot;2.5em&quot;,
                                                          }}
                                                        &gt;&lt;/span&gt;
                                                        &lt;span className=&quot;sizing reset-size3 size1 mtight&quot;&gt;
                                                          &lt;span className=&quot;mord mtight&quot;&gt;
                                                            3
                                                          &lt;/span&gt;
                                                        &lt;/span&gt;
                                                      &lt;/span&gt;
                                                    &lt;/span&gt;
                                                  &lt;/span&gt;
                                                &lt;/span&gt;
                                              &lt;/span&gt;
                                            &lt;/span&gt;
                                          &lt;/span&gt;
                                        &lt;/span&gt;
                                      &lt;/span&gt;
                                      &lt;span style={{ top: &quot;-3.23em&quot; }}&gt;
                                        &lt;span
                                          className=&quot;pstrut&quot;
                                          style={{ height: &quot;3em&quot; }}
                                        &gt;&lt;/span&gt;
                                        &lt;span
                                          className=&quot;frac-line&quot;
                                          style={{
                                            borderBottomWidth: &quot;0.04em&quot;,
                                          }}
                                        &gt;&lt;/span&gt;
                                      &lt;/span&gt;
                                      &lt;span style={{ top: &quot;-3.394em&quot; }}&gt;
                                        &lt;span
                                          className=&quot;pstrut&quot;
                                          style={{ height: &quot;3em&quot; }}
                                        &gt;&lt;/span&gt;
                                        &lt;span className=&quot;sizing reset-size6 size3 mtight&quot;&gt;
                                          &lt;span className=&quot;mord mtight&quot;&gt;
                                            &lt;span className=&quot;mord mtight&quot;&gt;
                                              &lt;span className=&quot;mord mathnormal mtight&quot;&gt;
                                                x
                                              &lt;/span&gt;
                                              &lt;span className=&quot;msupsub&quot;&gt;
                                                &lt;span className=&quot;vlist-t&quot;&gt;
                                                  &lt;span className=&quot;vlist-r&quot;&gt;
                                                    &lt;span
                                                      className=&quot;vlist&quot;
                                                      style={{
                                                        height: &quot;0.8913em&quot;,
                                                      }}
                                                    &gt;
                                                      &lt;span
                                                        style={{
                                                          top: &quot;-2.931em&quot;,
                                                          marginRight:
                                                            &quot;0.0714em&quot;,
                                                        }}
                                                      &gt;
                                                        &lt;span
                                                          className=&quot;pstrut&quot;
                                                          style={{
                                                            height: &quot;2.5em&quot;,
                                                          }}
                                                        &gt;&lt;/span&gt;
                                                        &lt;span className=&quot;sizing reset-size3 size1 mtight&quot;&gt;
                                                          &lt;span className=&quot;mord mtight&quot;&gt;
                                                            2
                                                          &lt;/span&gt;
                                                        &lt;/span&gt;
                                                      &lt;/span&gt;
                                                    &lt;/span&gt;
                                                  &lt;/span&gt;
                                                &lt;/span&gt;
                                              &lt;/span&gt;
                                            &lt;/span&gt;
                                          &lt;/span&gt;
                                        &lt;/span&gt;
                                      &lt;/span&gt;
                                      &lt;span className=&quot;vlist-s&quot;&gt;​&lt;/span&gt;
                                    &lt;/span&gt;
                                    &lt;span className=&quot;vlist-r&quot;&gt;
                                      &lt;span
                                        className=&quot;vlist&quot;
                                        style={{ height: &quot;0.4811em&quot; }}
                                      &gt;
                                        &lt;span&gt;&lt;/span&gt;
                                      &lt;/span&gt;
                                    &lt;/span&gt;
                                  &lt;/span&gt;
                                &lt;/span&gt;
                              &lt;/span&gt;
                              &lt;span className=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;
                            &lt;/span&gt;
                          &lt;/span&gt;
                          &lt;span className=&quot;mclose&quot;&gt;)&lt;/span&gt;
                        &lt;/span&gt;
                      &lt;/span&gt;
                    &lt;/span&gt;
                    &lt;span className=&quot;vlist-s&quot;&gt;​&lt;/span&gt;
                  &lt;/span&gt;
                  &lt;span className=&quot;vlist-r&quot;&gt;
                    &lt;span className=&quot;vlist&quot; style={{ height: &quot;0.8479em&quot; }}&gt;
                      &lt;span&gt;&lt;/span&gt;
                    &lt;/span&gt;
                  &lt;/span&gt;
                &lt;/span&gt;
              &lt;/span&gt;
              &lt;span className=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;
            &lt;/span&gt;
          &lt;/span&gt;
        &lt;/span&gt;
      &lt;/span&gt;
    &lt;/span&gt;
  &lt;/span&gt;
&lt;/div&gt;

&lt;p&gt;...What? Alpha? Theta with an inverted hat?&lt;/p&gt;
&lt;p&gt;Eventually, though, after rereading and rewriting these kinds of functions over and over, they also become easy to work with.&lt;/p&gt;
&lt;p&gt;In the excellent book &lt;em&gt;&lt;a href=&quot;https://www.manning.com/books/the-programmers-brain&quot;&gt;The Programmer&amp;#39;s Brain: What Every Programmer Needs to Know
About&lt;/a&gt;&lt;/em&gt;, Felienne Hermans does an amazing job of explaining the
different mechanisms that our brain uses to read, write, and understand code, as well as techniques to perform these
tasks as efficiently as possible.&lt;/p&gt;
&lt;p&gt;In short: the amount of &lt;em&gt;new&lt;/em&gt; information that our brains can handle is actually
pretty small, and there is not really much we can do about it.&lt;/p&gt;
&lt;p&gt;The good news is that our memory is very different from a computer — and we can take advantage of that. With enough
repetition, we eventually start to store patterns in our long-term memory and then use that knowledge to understand
new information &lt;em&gt;faster&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s why a skill becomes easier with more practice, be it math, playing the guitar, or
programming. The more we make things look and behave the same, the easier and faster it is to absorb them.&lt;/p&gt;
&lt;h2&gt;Why Should I Make My Elixir Code Predictable?&lt;/h2&gt;
&lt;p&gt;When it comes to understanding what we read and how well other people will understand the code that we write, being
predictable is essential.&lt;/p&gt;
&lt;p&gt;Three key elements make code predictable:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Structure:&lt;/strong&gt; different blocks of code &lt;em&gt;look&lt;/em&gt; and &lt;em&gt;behave&lt;/em&gt; the same. That is the main reason it is easy to understand a &lt;em&gt;for&lt;/em&gt; loop, even in languages that you&amp;#39;ve never used before.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Size:&lt;/strong&gt; smaller blocks (like functions, modules, classes, etc.) are easier to remember.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity:&lt;/strong&gt; less moving parts, like function parameters, help our brain keep track of what is happening.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One good example of predictability in the Elixir world is the &lt;a href=&quot;https://hexdocs.pm/plug/readme.html&quot;&gt;Plug library&lt;/a&gt; because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It uses &lt;a href=&quot;https://hexdocs.pm/elixir/1.4.5/behaviours.html&quot;&gt;behaviours&lt;/a&gt; to keep all implementations with the same
structure (expected input and output).&lt;/li&gt;
&lt;li&gt;Each plug is expected to be as small as possible since they add latency to the
HTTP response.&lt;/li&gt;
&lt;li&gt;They have a pretty simple shape: two functions, each with two parameters.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, what if we make our entire code predictable?&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Elixir&amp;#39;s Tools for Writing Predictable Code&lt;/h2&gt;
&lt;p&gt;Elixir itself has a couple of nice tools that, when used correctly, help us create predictable code: its pipe operator and &lt;code&gt;with&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;Keep in mind that neither of
these will &lt;em&gt;enforce&lt;/em&gt; a pattern or design principle — they are just tools.&lt;/p&gt;
&lt;h3&gt;Elixir&amp;#39;s Pipe Operator&lt;/h3&gt;
&lt;p&gt;The pipe &lt;code&gt;|&amp;gt;&lt;/code&gt; operator is an amazing tool that helps us express a chain of function calls as a simple sequence of
actions.&lt;/p&gt;
&lt;p&gt;Even if you&amp;#39;ve never written any Elixir code, you probably understand what this piece of code is trying to do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;form_params
|&amp;gt; validate_form()
|&amp;gt; insert_user()
|&amp;gt; report()
|&amp;gt; write_response()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s simple to read and easy to understand what is happening.&lt;/p&gt;
&lt;p&gt;However, because it&amp;#39;s so simple, we&amp;#39;re also very limited in what we can do with it. Since all functions are chained, they
depend on the previous result. If any of the functions break, there&amp;#39;s not much we can do about it unless we add
error handling to all of them.&lt;/p&gt;
&lt;p&gt;For a proper pipeline where we can handle errors and don&amp;#39;t want to make the functions dependent on one
another, it&amp;#39;s better to use the &lt;code&gt;with&lt;/code&gt; statement.&lt;/p&gt;
&lt;h3&gt;Elixir&amp;#39;s &lt;code&gt;with&lt;/code&gt; Statement&lt;/h3&gt;
&lt;p&gt;Pipe operators are simple, but we often need to check the return to ensure we have a valid state.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take the
previous example and rewrite it with a &lt;code&gt;with&lt;/code&gt; block:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;with %User{} = user_data &amp;lt;- validate_form(form_params),
     {:ok, user} &amp;lt;- insert_user(user_data),
     :ok &amp;lt;- report(user) do
  write_response(user)
else
  error -&amp;gt;
    report(error)
    handle_error(error)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have proper error handling and a chance to do something if our user data is invalid or it&amp;#39;s not
possible to insert the user. However, even in this simple example, it&amp;#39;s a bit harder to read because of the
added complexity. Note that since functions can return any value, we have to handle the return of each step explicitly.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s use a more complex example — a generic checkout code where we need information about the user, payment, and address — and
try to create an order:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;with %Payment{} = payment &amp;lt;- fetch_payment_information(params),
     {:ok, user} &amp;lt;- Session.get(conn, :user),
     address when !is_nil(address) &amp;lt;- fetch_address(user, params),
     {:ok, order} &amp;lt;- create_order(user, payment, address) do
  conn
  |&amp;gt; put_flash(:info, &amp;quot;Order completed!&amp;quot;)
  |&amp;gt; render(&amp;quot;checkout.html&amp;quot;)
else
  {:error, :payment_failed} -&amp;gt;
    handle_error(conn, &amp;quot;Payment Error&amp;quot;)

  %Store.OrderError{message: message} -&amp;gt;
    handle_error(conn, &amp;quot;Order Error&amp;quot;)

  error -&amp;gt;
    handle_error(conn, &amp;quot;Unprocessable order&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not only does each function have a different return type, but errors may also have different shapes.&lt;/p&gt;
&lt;p&gt;Also, because the existing
functions don&amp;#39;t follow a pattern, a developer adding a new step to this feature will not know what the new function
should return. A struct? ok/error tuple? A non-nil/nil value? What about errors?&lt;/p&gt;
&lt;p&gt;The lack of predictability here is bad
for whoever is reading this code, as well as people who will modify it in the future.&lt;/p&gt;
&lt;h2&gt;Design Better Pipelines in Elixir&lt;/h2&gt;
&lt;p&gt;As previously stated, to achieve predictability, we need three things in our code: structure, size, and
simplicity. Knowing that, we can create a few rules to help us write predictable code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Each function on a pipeline is expected to transform a given &lt;em&gt;state&lt;/em&gt; into an &lt;em&gt;updated state&lt;/em&gt;, and it should only do
one transformation. This will help us keep functions small and focused.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always receive two parameters&lt;/strong&gt;. The first parameter is the &lt;em&gt;state&lt;/em&gt; we want to transform, and the second contains any optional or extra data we might need to perform such a transformation. The second parameter is optional.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always return an ok/error tuple&lt;/strong&gt;. If everything goes well, an updated value of a state is returned.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For now, we won&amp;#39;t require a structure or type for the error description.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s revisit our checkout code, now applying these rules:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;options = %{conn: conn}

with {:ok, payment} &amp;lt;- fetch_payment_information(params, options),
     {:ok, user} &amp;lt;- fetch_user(conn),
     {:ok, address} &amp;lt;- fetch_address(%{user: user, params: params}, options),
     {:ok, order} &amp;lt;- create_order(%{user: user, address: address, payment: payment}, options)
  do
  conn
  |&amp;gt; put_flash(:info, &amp;quot;Order completed!&amp;quot;)
  |&amp;gt; redirect(to: Routes.order_path(conn, order))
else
  {:error, error_description} -&amp;gt;
    conn
    |&amp;gt; put_flash(:error, parse_error(error_description))
    |&amp;gt; render(&amp;quot;checkout.html&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It definitely looks better, and if someone in the future has to add a new step, they will know how this new function
should look. Because the errors always have the same shape, we just need to find the appropriate message for a
given error description, and everything else will look the same.&lt;/p&gt;
&lt;p&gt;However, although we&amp;#39;ve solved the design of one particular feature, none of these changes or design principles are
&lt;em&gt;enforced&lt;/em&gt;. A team working on a different part of your product might never have contact with this code and may follow
another design or pattern — or none at all.&lt;/p&gt;
&lt;p&gt;If we can find a way to enforce these changes, then the code will always look the same.&lt;/p&gt;
&lt;h3&gt;An Emerging Pattern&lt;/h3&gt;
&lt;p&gt;Now we can see a pattern emerging when we write our functions: chain-of-state
transformations — a &lt;em&gt;pipeline&lt;/em&gt;. It&amp;#39;s almost like an &lt;code&gt;Enum.reduce/3&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;However, instead of applying the same function to a collection of values, we apply a collection of functions to transform a state.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll explore this
pattern in greater detail in the next part of this series.&lt;/p&gt;
&lt;h2&gt;Coming Up Next Time: Enforcing Predictable Elixir Code&lt;/h2&gt;
&lt;p&gt;In this article, we showed how to write code in a pattern that our brains can understand faster and more
accurately. And by doing so, we also can write — and keep writing! — code that is maintainable in the long term.&lt;/p&gt;
&lt;p&gt;Note that this pattern does not cover module organization, project structure, or API design. For that, I highly
recommend the series of articles &lt;a href=&quot;https://medium.com/very-big-things/towards-maintainable-elixir-the-development-process-205ee257c109&quot;&gt;Towards Maintainable
Elixir&lt;/a&gt; by Saša
Jurić.&lt;/p&gt;
&lt;p&gt;In the next and final part of this two-part series, we&amp;#39;ll learn how to create a basic framework to enforce design principles in our Elixir code.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>LiveView Assigns: Three Common Pitfalls and Their Solutions</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/06/28/liveview-assigns-three-common-pitfalls-and-their-solutions.html"/>
    <id>https://blog.appsignal.com/2022/06/28/liveview-assigns-three-common-pitfalls-and-their-solutions.html</id>
    <published>2022-06-28T00:00:00+00:00</published>
    <updated>2022-06-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s take a look at three common LiveView assigns issues you might come across and how to fix them.</summary>
    <content type="html">&lt;p&gt;In the &lt;a href=&quot;https://blog.appsignal.com/2022/06/14/a-guide-to-phoenix-liveview-assigns.html&quot;&gt;first part&lt;/a&gt; of this two-part series, we examined LiveView assigns in detail — demystifying assigns, looking at some key concepts, and debugging.&lt;/p&gt;
&lt;p&gt;Now, we&amp;#39;ll turn our attention to three common mistakes that you might make with assigns and how to avoid them.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h3&gt;1. Evaluating All LiveView Assigns&lt;/h3&gt;
&lt;p&gt;As you pass assigns around to view helpers, and the complexity increases, you may need many assigns in
some functions. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;%= user_note(@user, @note, @theme, @locale) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you may be tempted to do the following instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;%= user_note(assigns) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem with this simplification is that it’ll completely ruin change tracking and, as a result, changing any
assign will trigger an update.&lt;/p&gt;
&lt;p&gt;To solve this, stick to passing only the required assigns explicitly and collapse multiple
arguments into a keyword list if needed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;%= user_note(@user, @note, theme: @theme, locale: @locale) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; LiveView itself hints at, and counters this problem by &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/0.15.0/Phoenix.LiveView.Socket.AssignsNotInSocket.html&quot;&gt;excluding all other
assigns&lt;/a&gt; from the widely
used &lt;code&gt;@socket&lt;/code&gt; struct in which they’re generally stored. But it does not forbid you from reaching for the &lt;code&gt;assigns&lt;/code&gt; directly,
opening a door to this issue.&lt;/p&gt;
&lt;h3&gt;2. Re-rendering Entire Lists&lt;/h3&gt;
&lt;p&gt;Change tracking on nested data such as lists is a complex problem, regardless of the framework. LiveView goes the extra
mile to represent &lt;code&gt;for&lt;/code&gt; loops via a &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Comprehension.html&quot;&gt;dedicated
struct&lt;/a&gt; so that static parts are only sent
once. But when it comes to assigns, it tracks all that appear in such loops as a whole.&lt;/p&gt;
&lt;p&gt;Our generated live resource in the &amp;#39;Caveman Debugging in LiveView&amp;#39; section of the &lt;a href=&quot;https://blog.appsignal.com/2022/06/14/a-guide-to-phoenix-liveview-assigns.html&quot;&gt;first part of this series&lt;/a&gt; re-evaluated every
table row and cell regardless of what we did with the &lt;code&gt;@notes&lt;/code&gt; assign.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;There’s a solution though. We can establish a separate tracking context using stateful live components. So let’s try
it out and create a component for each note:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.NotesLive.Index.NoteRow do
  use MyAppWeb, :live_component
  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;tr id={&amp;quot;note-#{@note.id}&amp;quot;}&amp;gt;
      &amp;lt;td&amp;gt;&amp;lt;%= inspect(Time.utc_now()) %&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;td&amp;gt;&amp;lt;%= inspect({Time.utc_now(), @note.name}) %&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;td&amp;gt;&amp;lt;%= inspect({Time.utc_now(), @note.content}) %&amp;gt;&amp;lt;/td&amp;gt;
      &amp;lt;!-- ACTIONS (CUT) --&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then render it within the table:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;table&amp;gt;
  &amp;lt;!-- TABLE HEADER (CUT) --&amp;gt;
  &amp;lt;tbody id=&amp;quot;notes&amp;quot;&amp;gt;
    &amp;lt;%= for note &amp;lt;- @notes do %&amp;gt; &amp;lt;.live_component module={__MODULE__.NoteRow}
    id={&amp;quot;note-row-#{note.id}&amp;quot;} note={note} /&amp;gt; &amp;lt;% end %&amp;gt;
  &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you may once again create, edit, and delete some notes for the following highly desired behavior:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When &lt;em&gt;creating&lt;/em&gt;, only the newly added row gets updated.&lt;/li&gt;
&lt;li&gt;When &lt;em&gt;editing&lt;/em&gt;, only the cells for changed fields get updated.&lt;/li&gt;
&lt;li&gt;When &lt;em&gt;deleting&lt;/em&gt;, no other rows get updated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: You should not have to worry about memory usage caused by copying assigns to live components. They reside on the
same process as the parent view, and so should share immutable data.&lt;/p&gt;
&lt;p&gt;The excellent article &lt;a href=&quot;https://thepugautomatic.com/2020/07/optimising-data-over-the-wire-in-phoenix-liveview/&quot;&gt;&lt;em&gt;Optimising data-over-the-wire in Phoenix LiveView&lt;/em&gt;&lt;/a&gt; compared Websocket payload for the naive loop vs. the component-based version. Note, however, that it
may not reflect the current state of affairs as these things are rapidly
evolving — &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view/blob/master/CHANGELOG.md#0173-2021-10-28&quot;&gt;see the Phoenix LiveView changelog&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;3. Growing LiveView Assigns Infinitely&lt;/h3&gt;
&lt;p&gt;As noted in the &amp;#39;LiveView Assigns Manage State&amp;#39; part of the &lt;a href=&quot;https://blog.appsignal.com/2022/06/14/a-guide-to-phoenix-liveview-assigns.html&quot;&gt;previous post&lt;/a&gt;, the server-side nature of LiveView places extra responsibilities on
memory management. For that reason, you can&amp;#39;t afford to grow lists infinitely, e.g., when paginating, as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.NotesLive do
  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;div id=&amp;quot;notes&amp;quot;&amp;gt;
      &amp;lt;%= for note &amp;lt;- @notes do %&amp;gt;
        &amp;lt;div id={&amp;quot;note-#{note.id}&amp;quot;}&amp;gt;
          &amp;lt;!-- CUT (note) --&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;% end %&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;button phx-click=&amp;quot;load_more&amp;quot;&amp;gt;Load more&amp;lt;/button&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
  def handle_event(&amp;quot;load_more&amp;quot;, _, socket) do
    next_page = socket.assigns.last_page + 1
    more_notes = Notes.list_notes(page: next_page)
    {:noreply, assign(socket,
      notes: socket.assigns.notes ++ more_notes,
      last_page: next_page
    )}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the memory usage will grow linearly, not just with the number of users (which is a problem we definitely don&amp;#39;t want
to have) but also with the total number of notes.&lt;/p&gt;
&lt;p&gt;The solution is to mark that
assign as temporary, switch to the &lt;code&gt;append&lt;/code&gt; update model for the note listing, and only assign new items:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.NotesLive do
  def mount(params, session, socket) do
    # ...
    {:ok, socket, temporary_assigns: [notes: []]}
  end
  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;div id=&amp;quot;notes&amp;quot; phx-update=&amp;quot;append&amp;quot;&amp;gt;
      &amp;lt;!-- CUT (notes loop) --&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
  def handle_event(&amp;quot;load_more&amp;quot;, _, socket) do
    next_page = socket.assigns.last_page + 1
    more_notes = Notes.list_notes(page: next_page)
    {:noreply, assign(socket,
      notes: more_notes,
      last_page: next_page
    )}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the notes list will still accumulate newly loaded records while keeping memory usage under control.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&quot;https://blog.appsignal.com/2022/06/14/a-guide-to-phoenix-liveview-assigns.html&quot;&gt;first part of this series&lt;/a&gt;, we spent some time diving into LiveView assigns. First, we demystified assigns,
before embarking on some caveman debugging and socket inspection.&lt;/p&gt;
&lt;p&gt;In this article, we examined three common pitfalls — evaluating all assigns, re-rendering entire lists, and growing assigns infinitely — and their solutions.&lt;/p&gt;
&lt;p&gt;I hope that this series has given you an idea of some trade-offs that come with LiveView assigns, alongside ways to get the most
out of the wonderful technology that Phoenix LiveView definitely is.&lt;/p&gt;
&lt;p&gt;Happy assigning!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A note from AppSignal&lt;/em&gt;: We&amp;#39;re very excited to have recently released &lt;a href=&quot;https://blog.appsignal.com/2022/06/20/appsignal-for-phoenix-2-1-automatic-liveview-instrumentation.html&quot;&gt;AppSignal for Phoenix 2.1&lt;/a&gt;, which adds automatic instrumentation for LiveView through Telemetry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Guide to Phoenix LiveView Assigns</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/06/14/a-guide-to-phoenix-liveview-assigns.html"/>
    <id>https://blog.appsignal.com/2022/06/14/a-guide-to-phoenix-liveview-assigns.html</id>
    <published>2022-06-14T00:00:00+00:00</published>
    <updated>2022-06-14T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s demystify LiveView assigns and see how they work in practice.</summary>
    <content type="html">&lt;p&gt;Phoenix LiveView lets you develop full-stack apps with client-side interactions while mostly avoiding
cross-stack hassle. Assigns, managed by the LiveView socket, are a core tool for making that happen — allowing you to store,
present, and update data effortlessly and efficiently. But as they do so much, assigns come with their
own complexities and may backfire if misused.&lt;/p&gt;
&lt;p&gt;Over the last three years, I&amp;#39;ve had the pleasure to work on multiple LiveView apps
within multiple teams, so I know first-hand that assigns can
feel like magic to many developers (myself included).&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;re going to demystify LiveView assigns. We&amp;#39;ll describe what LiveView assigns actually are in relation to popular frameworks,
find out how assigns work in practice, and highlight some of the traps that one may easily fall into.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Throughout this post, we&amp;#39;re going to use &lt;em&gt;assigns&lt;/em&gt; to refer to LiveView assigns — as
opposed to EEx assigns, Plug assigns, or Phoenix Socket assigns.&lt;/p&gt;
&lt;h2&gt;Demystifying Phoenix LiveView Assigns&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s start with an overview of what assigns actually are. Here&amp;#39;s a basic example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.StatsLive do
  use MyAppWeb, :live_view
  alias MyApp.{Accounts, Notes}

  def mount(params, session, socket) do
    {:ok, assign(socket,
      note_count: Notes.get_note_count(),
      user_count: Accounts.get_user_count()
    )}
  end

  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    Note count: &amp;lt;%= @note_count %&amp;gt;
    User count: &amp;lt;%= @user_count %&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above snippet shows how &lt;code&gt;@note_count&lt;/code&gt; and &lt;code&gt;@user_count&lt;/code&gt; are assigned initial values and then rendered as dynamic
fragments among the static HTML that surrounds them. That&amp;#39;s the concept of LiveView assigns in a nutshell.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s take a
deeper look, pointing out some similarities and differences between assigns and mainstream front-end development.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h3&gt;LiveView Assigns Provide Dynamic Input&lt;/h3&gt;
&lt;p&gt;Assigns in LiveView build on top of &lt;a href=&quot;https://hexdocs.pm/eex/EEx.html#module-macros&quot;&gt;those used by EEx&lt;/a&gt; as well as &lt;a href=&quot;https://hexdocs.pm/plug/Plug.Conn.html#module-connection-fields&quot;&gt;from &amp;quot;traditional&amp;quot; Phoenix&lt;/a&gt;. They are just input
variables — placeholders for dynamic data provided from the outside.&lt;/p&gt;
&lt;p&gt;Run the following code
from &lt;code&gt;iex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; EEx.eval_string(&amp;quot;Hello, &amp;lt;%= @name %&amp;gt;!&amp;quot;, assigns: [name: &amp;quot;John&amp;quot;])
&amp;quot;Hello, John!&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can easily compare assigns to props from React, Vue, or any other web component library. This is especially true
for stateless components that have recently switched to simple function syntax, like functional components in
React. Consider this simple component:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.MyComponents do
  def my_button(assigns = %{text: _, click: _}) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;button class=&amp;quot;some-class&amp;quot; phx-click={@click}&amp;gt;
      &amp;lt;%= @text %&amp;gt;
    &amp;lt;/button&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can surely imagine yourself rewriting it in any web component library with a very similar code structure and volume.
For the record, here&amp;#39;s how similar it&amp;#39;d be in React:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function MyButton({ text, click }) {
  return (
    &amp;lt;button class=&amp;quot;some-class&amp;quot; onClick={click}&amp;gt;
      {text}
    &amp;lt;/button&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component uses assigned input wherever it needs to, while the caller of &lt;code&gt;my_button&lt;/code&gt; provides it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;.my_button text=&amp;quot;Click me!&amp;quot; click=&amp;quot;some_event&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Easy enough, and no room for dilemmas. But that&amp;#39;s just the start.&lt;/p&gt;
&lt;h3&gt;LiveView Assigns Manage State&lt;/h3&gt;
&lt;p&gt;For live views and live components, assigns grow from being a dumb input into a long-lived state. As such, they derive
from &lt;a href=&quot;https://hexdocs.pm/phoenix/channels.html#overview&quot;&gt;Phoenix Channel assigns&lt;/a&gt;, and shift from props into state
in the React nomenclature.&lt;/p&gt;
&lt;p&gt;Views and components may opt to update their assigns from the inside to evolve their state. This is nothing fancy on its own, so — just like with props — we can easily find an equivalent
in any web component framework.&lt;/p&gt;
&lt;p&gt;What is fancy, however, is that in LiveView this happens on the server — taking advantage of Erlang processes to deliver
low latency at scale.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;To understand why this is great, let&amp;#39;s take a look at the following example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.UserSubscriptionLive do
  use MyAppWeb, :live_view

  # ...

  def handle_event(&amp;quot;pick_subscription&amp;quot;, params, socket) do
    # encrypted session
    %{assigns: %{current_user: user}} = socket

    # CSRF-protected user input
    %{&amp;quot;plan&amp;quot; =&amp;gt; plan} = params

    # ACID-safe database
    subscription = Subscriptions.create_subscription(user, plan)

    # non-public, secure APIs
    Payments.charge_user(user, subscription)

    # server-only background jobs
    Mailing.send_subscription_created_email(user, subscription)

    {:noreply, assign(socket, subscription: subscription})
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without any effort, we mix data from the session, user input, databases, APIs, background jobs, and PubSubs — in one place,
untampered, and server-side rendered. Presenting the results is just as simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haml&quot;&gt;&amp;lt;%= unless @subscription do %&amp;gt;
  Pick your plan:

  &amp;lt;a href=&amp;quot;#&amp;quot; phx-click=&amp;quot;pick_subscription&amp;quot; phx-value-plan=&amp;quot;basic&amp;quot;&amp;gt;Basic ($4.99)&amp;lt;/a&amp;gt;
  &amp;lt;a href=&amp;quot;#&amp;quot; phx-click=&amp;quot;pick_subscription&amp;quot; phx-value-plan=&amp;quot;premium&amp;quot;&amp;gt;Premium ($19.99)&amp;lt;/a&amp;gt;
&amp;lt;% else %&amp;gt;
  You&amp;#39;re currently subscribed to &amp;lt;%= format_plan(@subscription.plan) %&amp;gt; plan.

  &amp;lt;%= if @subscription.last_payment do %&amp;gt;
    You were last charged on &amp;lt;%= DateTime.to_date(@subscription.last_payment.inserted_at) %&amp;gt;.
  &amp;lt;% end %&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Imagine all the moving parts that it would take to produce and fully test the client-side equivalent of our
&lt;code&gt;@subscription&lt;/code&gt; assign. This is perhaps the biggest highlight of LiveView,
stealing the spotlight from API layers, state managers, sagas, and browser-based test suites.&lt;/p&gt;
&lt;p&gt;At the same time, state management is undoubtedly a challenging task, and keeping memory usage under control is one of
our main concerns. This is especially true considering we&amp;#39;re on the server, and all connected users will claim the memory
needed to hold the assigns during their entire session.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll examine a specific use case along with its solution in a moment.&lt;/p&gt;
&lt;h3&gt;LiveView Assigns Fuel Change Tracking&lt;/h3&gt;
&lt;p&gt;If you think that assigns are &amp;quot;just&amp;quot; props and state, and the show is over, brace yourself.&lt;/p&gt;
&lt;p&gt;You see, if you update a single React prop or piece of React state, the whole component will re-render. But LiveView assigns are different. The reason for this is HEEx — a
templating engine that splits your template into static and dynamic parts, and then only re-evaluates dynamic parts to
involve the changed assigns.&lt;/p&gt;
&lt;p&gt;Since this happens on the server, it&amp;#39;s only the actual changes that will ever take up bandwidth, saving you the effort needed to slim down JSON payloads in classic SPAs, e.g., by designing
case-specific or flexible APIs. That&amp;#39;s some cool out-of-the-box optimization.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; This feature is known by different names, including &lt;strong&gt;change tracking&lt;/strong&gt;, &lt;strong&gt;reactivity&lt;/strong&gt;, &lt;strong&gt;memoization&lt;/strong&gt;, or &lt;strong&gt;observability&lt;/strong&gt;. The approach towards it varies across JS frameworks — check out the above keywords regarding Angular, Ember, Knockout, or Svelte.&lt;/p&gt;
&lt;p&gt;In React, we can achieve similar behavior in a more explicit way (so it&amp;#39;ll serve as a great visual exercise)
with &lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#usememo&quot;&gt;&lt;code&gt;useMemo&lt;/code&gt;&lt;/a&gt;. Consider the following live component:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.UserHoroscope do
  use MyAppWeb, :live_component

  def render(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;div&amp;gt;
      &amp;lt;strong&amp;gt;Horoscope for {format_full_name(@first_name, @last_name)} (born on {format_date(@birthday)}):&amp;lt;/strong&amp;gt;
      {generate_horoscope(@birthday)}
    &amp;lt;/div&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Out of the box, it will only call &lt;code&gt;format_date&lt;/code&gt; or &lt;code&gt;get_horoscope&lt;/code&gt; when &lt;code&gt;@birthday&lt;/code&gt; changes, but not when either
&lt;code&gt;@first_name&lt;/code&gt; or &lt;code&gt;@last_name&lt;/code&gt; do (which may be extra useful if our generator that powers the horoscope becomes
complex and the user name changes). The same goes for the other &lt;code&gt;&amp;lt;%= ... %&amp;gt;&lt;/code&gt; snippets.&lt;/p&gt;
&lt;p&gt;With React, we start off with the following naive component that runs all helper functions, regardless of
changes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function UserHoroscope({ firstName, lastName, birthday }) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;strong&amp;gt;
        Horoscope for {formatFullName(firstName, lastName)} (born on{&amp;quot; &amp;quot;}
        {formatDate(birthday)}):
      &amp;lt;/strong&amp;gt;
      {getHoroscope(birthday)}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we&amp;#39;d extend it into the following shape with &lt;code&gt;useMemo&lt;/code&gt; so that each helper is called only when its dependencies
change:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function UserHoroscope({ firstName, lastName, birthday }) {
  const fullName = useMemo(() =&amp;gt; {
    return formatFullName(firstName, lastName);
  }, [firstName, lastName]);

  const formattedBirthday = useMemo(() =&amp;gt; {
    return formatDate(birthday);
  }, [birthday]);

  const horoscope = useMemo(() =&amp;gt; {
    return generateHoroscope(birthday);
  }, [birthday]);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;strong&amp;gt;
        Horoscope for {fullName} (born on {formattedBirthday}):
      &amp;lt;/strong&amp;gt;
      {horoscope}
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; We&amp;#39;re not saying React is the worst here. React focuses on optimizing historically slow DOM patching while assuming that modern JS is fast enough to re-evaluate typical rendering logic (ideal for a client-side library). LiveView goes the extra mile to save on server resources and bandwidth without sacrificing the dev experience — which works well for a compiler-backed server-side library.&lt;/p&gt;
&lt;p&gt;Overall, change tracking is a powerful feature that does some really useful stuff under the hood while keeping our code clean. But it may also raise some ambiguity and doubts as far as assigns are concerned, and, if used without care, change tracking can definitely backfire performance-wise.&lt;/p&gt;
&lt;h2&gt;Taking LiveView Assigns for a Spin&lt;/h2&gt;
&lt;p&gt;Now that we know multiple concepts are mixed in with assigns, we see how they may actually not be as simple as they look in the code.&lt;/p&gt;
&lt;p&gt;LiveView docs have a dedicated &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/assigns-eex.html&quot;&gt;assigns and HEEx guide&lt;/a&gt;, so that&amp;#39;s
the first place you should look for answers and pointers. The module page for the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Engine.html&quot;&gt;template engine&lt;/a&gt; gives some extra insight.&lt;/p&gt;
&lt;p&gt;But, sooner or later
(and I&amp;#39;d put my bets on sooner considering the early stage of LiveView), that isn&amp;#39;t enough. Let&amp;#39;s look at how to
approach LiveView to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Play with it and boost your confidence&lt;/li&gt;
&lt;li&gt;Debug and fix suspicious behavior in a real app&lt;/li&gt;
&lt;li&gt;Check for optimizations or regressions in new LiveView releases&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Caveman Debugging in LiveView&lt;/h3&gt;
&lt;p&gt;The first technique that you may want to employ involves returning to the very roots of debugging. You&amp;#39;ll use a battle-proven,
highly sophisticated technique that&amp;#39;s been hiding in the darkest corners of the internet under numerous inspiring names
like &lt;a href=&quot;https://stackoverflow.com/a/189639&quot;&gt;&amp;#39;caveman debugging&amp;#39;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea is to rely on the fact that HEEx only re-evaluates a subset of code blocks and to output a timestamp as close
as possible to the place you want to inspect in the template.&lt;/p&gt;
&lt;p&gt;To try it out, generate a sample live resource for testing in your Phoenix 1.6 app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix phx.gen.live Notes Note notes name:string content:text
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apply the printed instructions and navigate to &lt;code&gt;/notes&lt;/code&gt;. Then add the following &lt;code&gt;inspect/1&lt;/code&gt; calls to your
&lt;code&gt;index.html.heex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;%= inspect({Time.utc_now(), :above_notes}) %&amp;gt;
&amp;lt;table&amp;gt;
  &amp;lt;!-- CUT (table header) --&amp;gt;
  &amp;lt;tbody id=&amp;quot;notes&amp;quot;&amp;gt;
    &amp;lt;%= for note &amp;lt;- @notes do %&amp;gt;
      &amp;lt;tr id={&amp;quot;note-#{note.id}&amp;quot;}&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;%= inspect(Time.utc_now()) %&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;%= inspect({Time.utc_now(), note.name}) %&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;%= inspect({Time.utc_now(), note.content}) %&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;!-- CUT (actions cell) --&amp;gt;
      &amp;lt;/tr&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now try adding and removing some notes. In the default generated live resource, you should notice that the
&lt;code&gt;:above_notes&lt;/code&gt; timestamp updates together with all the per-row ones when creating or editing notes, but not when
deleting them.&lt;/p&gt;
&lt;p&gt;This hints that something different is happening with the live view and its assigns for the delete case. And rightfully so. When you look at the code, &lt;code&gt;FormComponent&lt;/code&gt; uses &lt;code&gt;push_redirect/2&lt;/code&gt; upon a save, causing the whole index to reload, while
&lt;code&gt;Index&lt;/code&gt; uses &lt;code&gt;assign/2,3&lt;/code&gt; upon deletion to only update that specific assign.&lt;/p&gt;
&lt;p&gt;If you want to avoid the reload, it&amp;#39;s as simple as replacing &lt;code&gt;push_redirect/2&lt;/code&gt; in &lt;code&gt;FormComponent&lt;/code&gt; with &lt;code&gt;push_patch/2&lt;/code&gt;,
plus reloading the &lt;code&gt;@notes&lt;/code&gt; assign in &lt;code&gt;Index&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp apply_action(socket, :index, _params) do
  socket
  |&amp;gt; assign(:page_title, &amp;quot;Listing Notes&amp;quot;)
  |&amp;gt; assign(:notes, list_notes())
  |&amp;gt; assign(:note, nil)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Voilà: your first performance tweak!&lt;/p&gt;
&lt;p&gt;You may also have noticed that all per-row timestamps re-render when you create, edit, and delete notes — regardless
of whether a specific note is affected or not. We&amp;#39;ll get back to this later.&lt;/p&gt;
&lt;h3&gt;Socket Inspection&lt;/h3&gt;
&lt;p&gt;Sometimes, it&amp;#39;s useful to see what LiveView pushes down the wire. This isn&amp;#39;t so easy to visually tie to specific
places on the page. But it allows us to inspect what is getting updated, and when, without template changes, and — this is
especially useful — to see payload size and structure.&lt;/p&gt;
&lt;p&gt;In order to inspect a socket:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Visit your live view in Chrome.&lt;/li&gt;
&lt;li&gt;Open Developer Tools.&lt;/li&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Optionally filter by the &lt;strong&gt;WS&lt;/strong&gt; type.&lt;/li&gt;
&lt;li&gt;Choose the &lt;code&gt;websocket?_csrf_token=...&lt;/code&gt; name.&lt;/li&gt;
&lt;li&gt;Switch to the &lt;strong&gt;Messages&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Choose the message that you&amp;#39;re interested in.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;#39;s how it might look:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-06/live-websocket-inspect-devtools.png&quot; alt=&quot;Chrome devtools showing the LiveView rendering payload for two notes.&quot;/&gt;&lt;/p&gt;
&lt;p&gt;When working with two notes, the highlighted piece of inbound payload is responsible for filling the listing. This
confirms that the entire listing is re-rendered,
regardless of operation.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; You may find it more handy to ask LiveView&amp;#39;s JS client to log updates to the console, by calling &lt;code&gt;liveSocket.enableDebug()&lt;/code&gt; in it.&lt;/p&gt;
&lt;p&gt;In the end, having insight into the raw payload can lead you to some case-specific optimizations, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Restructuring the assigns (e.g., by breaking apart large or nested ones)&lt;/li&gt;
&lt;li&gt;Using live components (to ensure some assigns are tracked separately)&lt;/li&gt;
&lt;li&gt;Sending some data to JavaScript hooks as binary (by switching to &lt;a href=&quot;https://hexdocs.pm/phoenix/channels.html&quot;&gt;Phoenix.Channel&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Debugging in Production with AppSignal&lt;/h2&gt;
&lt;p&gt;The caveman technique is great for a single developer working on an application that hasn&amp;#39;t been pushed to production. However, if you have an app in production with live users, you may want to take a look at &lt;a href=&quot;https://appsignal.com/&quot;&gt;AppSignal&lt;/a&gt; for monitoring your application performance and checking for errors in production.
&lt;a href=&quot;https://docs.appsignal.com/elixir/installation/#installing-the-package&quot;&gt;Adding AppSignal to an existing application&lt;/a&gt; takes a few seconds, and you can track LiveView errors from there.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s an example of the AppSignal dashboard collecting data from a sample application:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-04/appsignal.png&quot; alt=&quot;AppSignal Screenshot&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;In this post, we started off by demystifying LiveView assigns, before touching on some cross-over between assigns and mainstream front-end development. Finally, we explored caveman debugging in LiveView and socket inspection.&lt;/p&gt;
&lt;p&gt;LiveView combines a lot of functionality in assigns, including some that&amp;#39;s just as clever and useful as it is implicit
and complex.&lt;/p&gt;
&lt;p&gt;The key is to get a grasp on the key concepts, which are all relatable to what we can find in client-side frameworks. And,
considering the framework&amp;#39;s young age, to have a fallback solution for when existing resources can&amp;#39;t help — a way to
dig into it on your own.&lt;/p&gt;
&lt;p&gt;Next up in this two-part series, we&amp;#39;ll look at some common pitfalls when it comes to LiveView assigns.&lt;/p&gt;
&lt;p&gt;Until then, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Algebraic Data Types in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/05/31/algebraic-data-types-in-elixir.html"/>
    <id>https://blog.appsignal.com/2022/05/31/algebraic-data-types-in-elixir.html</id>
    <published>2022-05-31T00:00:00+00:00</published>
    <updated>2022-05-31T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover the ins and outs of ADTs and their benefits for your Elixir app.</summary>
    <content type="html">&lt;p&gt;Elixir is a dynamically-typed language. Types in Elixir are checked when a program runs, not when it compiles. If they don’t match up, an exception is thrown.&lt;/p&gt;
&lt;p&gt;In statically-typed languages, types are checked during compile time. This can help us write code that is correct, understandable, and refactorable.&lt;/p&gt;
&lt;p&gt;But it also introduces a certain focus on types as the foundation for your application. One interesting concept is to use types to model your business domain. In languages like Haskell, F#, and OCaml, this is usually done with algebraic data types (ADTs) — they build compound data types by aggregating types with product (AND) and sum (OR) types.&lt;/p&gt;
&lt;p&gt;With the help of Dialyzer, a static analysis tool, you can use ADTs to constrain the number of your application&amp;#39;s allowed states. This decreases the chance that errors will slip in.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll cover Dialyzer, ADTs, and how you can solve the problem of illegal states by using them together.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Type Declarations in Elixir with Dialyzer&lt;/h2&gt;
&lt;p&gt;In Elixir (and other BEAM languages), checking type specifications is usually done with &lt;a href=&quot;https://www.erlang.org/doc/man/dialyzer.html&quot;&gt;Dialyzer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dialyzer is different from the type systems of Haskell, OCaml, or even TypeScript. Instead of you proving to the compiler that your code is correct, Dialyzer needs to prove to you that your code is not correct.&lt;/p&gt;
&lt;p&gt;This makes Dialyzer rather lax in requirements. If there is a way for the types to work, Dialyzer will assume you know what you are doing, and the types will, indeed, work.&lt;/p&gt;
&lt;p&gt;But it’s still useful to reason about types and catch the occasional mistake.&lt;/p&gt;
&lt;h2&gt;Quick Intro to Dialyzer in Elixir&lt;/h2&gt;
&lt;p&gt;You can use Dialyzer in Elixir by adding a type spec for your functions via &lt;code&gt;@spec&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#          (1)      (2)           (3)
  @spec plus_one(integer) :: integer

  def plus_one(x), do: x + 1
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we just write the name of the function (1) with its type as an argument (2), then the return type of the function (3).&lt;/p&gt;
&lt;p&gt;You can find a &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/typespecs.html#basic-types&quot;&gt;list of basic types to use in Elixir&amp;#39;s documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can also create your own type aliases via &lt;code&gt;@type&lt;/code&gt;. To do that, you need to provide the alias&amp;#39; name (1) and its type (2).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#         (1)        (2)
  @type counter :: integer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you use the Elixir language server, that’s all you need to do: your plugin/extension will notify you about any specs that Dialyzer doesn’t like. Otherwise, you need to run the &lt;code&gt;mix dialyzer&lt;/code&gt; task to check your types.&lt;/p&gt;
&lt;p&gt;You can find more about &lt;a href=&quot;https://elixir-lang.org/getting-started/typespecs-and-behaviours.html&quot;&gt;the use of Dialyzer on Elixir&amp;#39;s website&lt;/a&gt; and in &lt;a href=&quot;https://hexdocs.pm/elixir/1.13/typespecs.html&quot;&gt;Elixir&amp;#39;s typespec docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that we can type spec our Elixir code, let’s dig into algebraic data types.&lt;/p&gt;
&lt;h2&gt;Algebraic Data Types&lt;/h2&gt;
&lt;p&gt;While the name sounds scary (ooh, algebra 👻), algebraic data types are relatively simple.&lt;/p&gt;
&lt;p&gt;This section will focus on the two main parts of ADTs: product (AND) and sum (OR) types.&lt;/p&gt;
&lt;h3&gt;Product Types&lt;/h3&gt;
&lt;p&gt;Product types are all around us. A product type is just a type with two or more fields that each hold a data type. You can also think of them as AND types.&lt;/p&gt;
&lt;p&gt;For example, a tuple is a product type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type tuple(a, b) :: {a, b}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It takes two data types — a &lt;strong&gt;and&lt;/strong&gt; b — and returns a type that holds both of these data types.&lt;/p&gt;
&lt;p&gt;In Elixir, we also use product types with named fields — structs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Person do
  defstruct first_name: &amp;quot;Gints&amp;quot;, last_name: &amp;quot;Dreimanis&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s look at the type in this example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type t() :: %__MODULE__{
        first_name: String.t(),
        last_name: String.t()
      }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generally, you can think of types as being sets of possible values. For example, a boolean has two possible values: &lt;code&gt;:true&lt;/code&gt; and &lt;code&gt;:false&lt;/code&gt;. A type for a traffic light color has one of three possible values: &lt;code&gt;:green&lt;/code&gt;, &lt;code&gt;:yellow&lt;/code&gt;, and &lt;code&gt;:red&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If we have two types with sizes &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt;, then the product type of those types will contain &lt;code&gt;a * b&lt;/code&gt; values — the product of the sizes of those types. If you make a product type of the boolean and traffic light types — e.g., put a boolean and traffic light in a tuple — you&amp;#39;ll have &lt;code&gt;2 * 3 = 6&lt;/code&gt; possible values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:green, :true}
{:yellow, :true}
{:red, :true}
{:green, :false}
{:yellow, :false}
{:red, :false}
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Sum Types&lt;/h3&gt;
&lt;p&gt;A historically less common kind of type is sum types.&lt;/p&gt;
&lt;p&gt;In contrast to a product type, a sum type gives you one of two (or more) options. You can also think of them as OR types.&lt;/p&gt;
&lt;p&gt;We use these in Elixir as well. For example, result tuples are sum types.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type result(a, b) :: {:error, a} | {:ok, b}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a result tuple, we can have an error of type &lt;code&gt;a&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; success of type &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Or, for example, we can have a sum type for optional values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type optional(a) :: :error | {:ok, a}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it can also just be used for making lists of alternatives.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type direction :: :north | :west | :south | :east
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you list two types in a sum type, the resulting type can pick a type from one set of values or the other. Because of this, its size is generally the sum of the sizes of those types.&lt;/p&gt;
&lt;p&gt;The above might not always be true when using Dialyzer: you can put together two sets that overlap. For the statement to be true, they need to be tagged with the set they come from — the result type we defined above is a prime example.&lt;/p&gt;
&lt;p&gt;That’s what people usually mean by algebraic data types.&lt;/p&gt;
&lt;h3&gt;There&amp;#39;s More to Algebraic Data Types&lt;/h3&gt;
&lt;p&gt;By putting together sums and products, we have something akin to the algebra that we know and love from our school days: multiplication, sums, and variables.&lt;/p&gt;
&lt;p&gt;Of course, there is more to algebraic types than just this: there’s also recursion, exponentials, etc. If you want to delve deeper into the subject, check out how they look in languages like Haskell.&lt;/p&gt;
&lt;p&gt;Here are two Haskell articles that you can read: one from &lt;a href=&quot;https://codewords.recurse.com/issues/three/algebra-and-calculus-of-algebraic-data-types&quot;&gt;Joel Burget on the algebra of ADTs&lt;/a&gt; and &lt;a href=&quot;https://serokell.io/blog/algebraic-data-types-in-haskell&quot;&gt;an ADTs in Haskell tutorial from yours truly&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;How Algebraic Data Types Help in Domain Modeling&lt;/h2&gt;
&lt;p&gt;We Elixir programmers usually don’t think in terms of sum types. The primary tool for modeling a domain in Elixir is the struct, a product type with named fields.&lt;/p&gt;
&lt;p&gt;While that&amp;#39;s good enough for most things, sometimes it is beneficial to use sum types as well.&lt;/p&gt;
&lt;p&gt;Let’s look at an example.&lt;/p&gt;
&lt;h3&gt;Custom Kanban Board&lt;/h3&gt;
&lt;p&gt;Let’s imagine we need to create a representation of a customized Kanban board issue.&lt;/p&gt;
&lt;p&gt;Our issues can be in one of these states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Searching for assignee: in this case, it should have neither an assignee nor a reviewer&lt;/li&gt;
&lt;li&gt;Not started yet: in this and the following state, it should have an assignee but not a reviewer&lt;/li&gt;
&lt;li&gt;In progress&lt;/li&gt;
&lt;li&gt;In review: in this and the following state, it should have an assignee and a reviewer&lt;/li&gt;
&lt;li&gt;Done&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All issues also have names and descriptions.&lt;/p&gt;
&lt;p&gt;At first, one might be tempted to use a simple struct.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Issue do
  defstruct name: &amp;quot;&amp;quot;,
            description: &amp;quot;&amp;quot;,
            state: :searching_for_assignee
            assignee: nil,
            reviewer: nil
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But as we saw in the section on product types, a simple product type has a lot of possible values, some of which might not match our requirements.&lt;/p&gt;
&lt;p&gt;For example, we can create an issue that searches for an assignee but still has an assignee and a reviewer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;iex(1)&amp;gt; %Issue{name: &amp;quot;wrong issue&amp;quot;, description: &amp;quot;not good at all&amp;quot;, state: :searching_for_assignee, assignee: &amp;quot;Jorge Luis Borges&amp;quot;, reviewer: &amp;quot;Gabriel García Márquez&amp;quot;}
%Issue{
  assignee: &amp;quot;Jorge Luis Borges&amp;quot;,
  description: &amp;quot;not good at all&amp;quot;,
  name: &amp;quot;wrong issue&amp;quot;,
  reviewer: &amp;quot;Gabriel García Márquez&amp;quot;,
  state: :searching_for_assignee
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While it is possible to avoid doing that generally, it is simpler to make it impossible. We have a saying for this: “make illegal states unrepresentable”.&lt;/p&gt;
&lt;p&gt;To do that, we need to create a sum type that covers all the states that we want to allow. It will enable us to cut out some of the wrong states by substituting products of values with sums of values.&lt;/p&gt;
&lt;p&gt;First, let’s combine the &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;assignee&lt;/code&gt;, and &lt;code&gt;reviewer&lt;/code&gt; fields into one field: &lt;code&gt;state&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defstruct name: &amp;quot;&amp;quot;,
          description: &amp;quot;&amp;quot;,
          state: :searching_for_assignee
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, let’s define a sum type for &lt;code&gt;state&lt;/code&gt; that will contain our specified options.&lt;/p&gt;
&lt;p&gt;Let’s look at them again. Our issue can be in one of these states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Searching for assignee&lt;/li&gt;
&lt;li&gt;Not started yet but with an assignee&lt;/li&gt;
&lt;li&gt;In progress and with an assignee&lt;/li&gt;
&lt;li&gt;In review with an assignee and reviewer&lt;/li&gt;
&lt;li&gt;Done, with the assignee and reviewer left for the historical record&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s quite easy to define a type that reads almost like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type state ::
        :searching_for_assignee
        | {:not_started, String.t()}
        | {:in_progress, String.t()}
        | {:in_review, String.t(), String.t()}
        | {:done, String.t(), String.t()}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So that it&amp;#39;s simpler to understand, we can create aliases for the assignee and reviewer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type assignee :: String.t()
@type reviewer :: String.t()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, the type looks exactly like our list of rules.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type state ::
        :searching_for_assignee
        | {:not_started, assignee}
        | {:in_progress, assignee}
        | {:in_review, assignee, reviewer}
        | {:done, assignee, reviewer}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All that&amp;#39;s left is to create a type specification for the module struct (&lt;code&gt;Issue&lt;/code&gt;) by using our state type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@type t() :: %__MODULE__{
        name: String.t(),
        description: String.t(),
        state: state
      }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here’s the complete module code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Issue do
  defstruct name: &amp;quot;&amp;quot;,
            description: &amp;quot;&amp;quot;,
            state: :searching_for_assignee

  @type assignee :: String.t()
  @type reviewer :: String.t()
  @type state ::
          :searching_for_assignee
          | {:not_started, assignee}
          | {:in_progress, assignee}
          | {:in_review, assignee, reviewer}
          | {:done, assignee, reviewer}

  @type t() :: %__MODULE__{
          name: String.t(),
          description: String.t(),
          state: state
        }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can test whether this type specification can stop us from making a logic error.&lt;/p&gt;
&lt;p&gt;We’ll create a function that adds a reviewer to the issue, but we’ll slip a bug inside: it will not change the state of the issue. We’ll also add a type spec.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;@spec add_assignee(Issue.t(), assignee) :: Issue.t()
def add_assignee(%{state: :searching_for_assignee} = issue, assignee_name) do
  %{issue | state: {:searching_for_assignee, assignee_name}}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dialyzer will correctly return a type error here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;lib/issue.ex:21:invalid_contract
The @spec for the function does not match the success typing of the function.

Function:
Issue.add_assignee/2

Success typing:
@spec add_assignee(%{:state =&amp;gt; :searching_for_assignee, _ =&amp;gt; _}, _) :: %{
  :state =&amp;gt; {:searching_for_assignee, _},
  _ =&amp;gt; _
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s a bit cryptic, but it basically means that &lt;code&gt;Issue.add_assignee&lt;/code&gt; didn’t compile, and we should look into it! 🙃&lt;/p&gt;
&lt;p&gt;As you can see, algebraic data types have saved us from making an error. Turns out, they’re not really a scary monster but a friend.&lt;/p&gt;
&lt;h2&gt;Benefits of Algebraic Data Types for Your Elixir App&lt;/h2&gt;
&lt;p&gt;Adopting algebraic data types for your Elixir applications is a two-step decision process.&lt;/p&gt;
&lt;p&gt;The first step is to choose to use Dialyzer and typespecs. Dialyzer gives most of the benefits that any language with static typing would:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;#39;s easier to catch errors you&amp;#39;ve made in code.&lt;/li&gt;
&lt;li&gt;Types give extra information about code: what it does and what values it operates. This is helpful when trying to understand the code.&lt;/li&gt;
&lt;li&gt;Once you have written your code, types can ensure the code still does the same thing (similar to tests) so it is easier to refactor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you&amp;#39;ve adopted Dialyzer for your codebase, thinking in terms of algebraic data types should come naturally, and give a few benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As we have seen in the example, sum types in particular let you cut down the possible states and make illegal states unrepresentable.&lt;/li&gt;
&lt;li&gt;Having AND and OR in your vocabulary helps you build compound types in a way that&amp;#39;s intuitive and understandable even to non-developers (domain experts).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, ADTs are just one tool for software correctness — definitely not a panacea. But in general, ADTs are a helpful concept for anyone working with an Elixir codebase that uses Dialyzer.&lt;/p&gt;
&lt;p&gt;If your codebase doesn&amp;#39;t use Dialyzer, your first goal should be to introduce it, which is a much larger undertaking than changing how you do types when writing type specifications. That undertaking is unfortunately out of the scope of this article.&lt;/p&gt;
&lt;p&gt;If you want to learn more about how ADTs can make your code clearer and help you ship better code, I invite you to check out &lt;a href=&quot;https://pragprog.com/titles/swdddf/domain-modeling-made-functional/&quot;&gt;Domain Modeling Made Functional&lt;/a&gt; by Scott Wlaschin or his blog post series called &lt;a href=&quot;https://fsharpforfunandprofit.com/series/designing-with-types/&quot;&gt;Designing with Types&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;ADTs in Elixir: Wrap Up and Further Reading&lt;/h2&gt;
&lt;p&gt;In this post, we explored how to check type specifications with Dialyzer, before focusing on the two main parts of ADTs: product (AND) and sum (OR) types.&lt;/p&gt;
&lt;p&gt;We then turned to the use of ADTs in domain modeling and finally touched on the benefits of ADTs.&lt;/p&gt;
&lt;p&gt;If you want to explore algebraic data types, the best option is to get accustomed to a statically-typed functional language such as Haskell, OCaml, or F#.&lt;/p&gt;
&lt;p&gt;Each of those languages has excellent materials for using types as the foundation of your code. The resource that would vibe the best with Elixir developers is probably the aforementioned &lt;a href=&quot;https://pragprog.com/titles/swdddf/domain-modeling-made-functional/&quot;&gt;Domain Modeling Made Functional&lt;/a&gt; since it also covers domain-driven design, which can confuse new Phoenix developers.&lt;/p&gt;
&lt;p&gt;Elixir also has a library that emulates algebraic data types called &lt;a href=&quot;https://github.com/witchcrafters/algae&quot;&gt;Algae&lt;/a&gt;, which we used in one of our previous articles — &lt;a href=&quot;https://blog.appsignal.com/2022/02/08/functional-programming-in-elixir-with-witchcraft.html&quot;&gt;Functional Programming in Elixir with Witchcraft&lt;/a&gt;. In general, Algae provides better tools than Dialyzer to build up a tower of abstractions from simple building blocks. Brave readers might find it rewarding to experiment with.&lt;/p&gt;
&lt;p&gt;Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Livebook for Elixir: Just What the Docs Ordered</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/05/24/livebook-for-elixir-just-what-the-docs-ordered.html"/>
    <id>https://blog.appsignal.com/2022/05/24/livebook-for-elixir-just-what-the-docs-ordered.html</id>
    <published>2022-05-24T00:00:00+00:00</published>
    <updated>2022-05-24T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Check out some top tips for using Livebook in Elixir and find out how to create interactive docs.</summary>
    <content type="html">&lt;p&gt;While initially conceived as a tool for data exploration (much like &lt;a href=&quot;https://jupyter.org/&quot;&gt;Jupyter&lt;/a&gt; for Python), Livebook has deservedly become a sensation in the Elixir community.&lt;/p&gt;
&lt;p&gt;It has been fantastic to see all the wonderful ways teams are leveraging Livebook for a range of different use cases. We have seen Livebooks being used to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create interactive documentation for libraries.&lt;/li&gt;
&lt;li&gt;Build onboarding material and guides.&lt;/li&gt;
&lt;li&gt;Audit and explore potential dependencies in your app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Livebooks have also been used as the default REPL interface for project development.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll show how you can easily create interactive documentation with Livebook and outline some top tips for using Livebook. We will assume you have &lt;a href=&quot;https://Github.com/livebook-dev/livebook&quot;&gt;installed Livebook&lt;/a&gt;, following the guidance in their README.&lt;/p&gt;
&lt;h2&gt;But First: What is Livebook for Elixir?&lt;/h2&gt;
&lt;p&gt;Livebooks are supercharged markdown files where you can add sections of arbitrary executable Elixir code. They are inspired by similar notebooks for other languages (like Python&amp;#39;s Jupyter), but Livebooks leverage &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html&quot;&gt;LiveView&lt;/a&gt; and other BEAM goodies, so they are even better.&lt;/p&gt;
&lt;p&gt;Livebook files get their own &lt;code&gt;.livemd&lt;/code&gt; extension, and (somewhat confusingly) we create and run those Livebook markdown files using a Phoenix application also called &lt;a href=&quot;https://Github.com/livebook-dev/livebook&quot;&gt;Livebook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That phoenix app runs in the browser and enables a whole host of interactive features like collaboration, as we will see.&lt;/p&gt;
&lt;p&gt;The expectation is that you will install the Livebook repo locally and start a Livebook server from somewhere on your machine where there are Livebooks (the files).&lt;/p&gt;
&lt;p&gt;The Livebook app will show you the working directory of where you started the Livebook server, so you can select any given Livebook to run from there.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s now look at a library to document.&lt;/p&gt;
&lt;h2&gt;Livebook Docs: A Single Source of Truth in Elixir&lt;/h2&gt;
&lt;p&gt;Our library is going to accept various inputs and rate them according to the following chonk chart:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-05/chonk.jpg&quot; alt=&quot;alt chart showing cats of various sizes&quot;/&gt;&lt;/p&gt;
&lt;p&gt;It will output the chonk rating accordingly. First, let&amp;#39;s create the library.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mix new chonk_o_meter &amp;amp;&amp;amp; cd chonk_o_meter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s add &lt;code&gt;ex_doc&lt;/code&gt; to our deps in our &lt;code&gt;mix.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:ex_doc, &amp;quot;&amp;gt;= 0.0.0&amp;quot;, runtime: false, only: [:docs, :dev]},
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, download the chonk chart image above and put it into the root of the library in a directory called &lt;code&gt;images&lt;/code&gt; so we can refer to it in our README. In the &lt;code&gt;README.md&lt;/code&gt;, let&amp;#39;s put a title and a short explanation of what the library aims to do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# Chonk &amp;#39;O&amp;#39; Meter

Chonk O Meter is a state-of-the-art size estimator. It will rate the size of anything according to the following chart:

![alt chart showing cats of various sizes](./images/chonk.jpg)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far, so good. Now we will open the module and write our moduledoc. But here&amp;#39;s the thing: what we really want to do is just copy what we already wrote for the README.&lt;/p&gt;
&lt;p&gt;Having one source of truth for that information is super valuable as the library develops because having to update the documentation in multiple places is a recipe for errors!&lt;/p&gt;
&lt;p&gt;It&amp;#39;s good to repeat the same information in different formats because different people will come to the library via different paths.&lt;/p&gt;
&lt;p&gt;Some may see the repo first (and therefore the README), whereas others may see the library on Hex first — and so only see the moduledoc.&lt;/p&gt;
&lt;p&gt;You may think that it&amp;#39;s easy enough to copy and paste, but once we add our Livebook into the mix, there will be three places we need to update docs when something changes!&lt;/p&gt;
&lt;p&gt;Instead, let&amp;#39;s be a bit smarter. We will section off a part of the README and read that section into the moduledoc at compile time. Sandwich the introduction to the library between two markdown comments in the README:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;&amp;lt;!-- README START --&amp;gt;

.... Library introduction here.

&amp;lt;!-- README END --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can write the introduction as if it were a moduledoc in between those two comments, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;&amp;lt;!-- README START --&amp;gt;

Chonk O Meter is a state-of-the-art size estimator. It will rate the size of anything according to the following chart:

![alt chart showing cats of various sizes](./images/chonk.jpg)

&amp;lt;!-- README END --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the main module &lt;code&gt;ChonkOMeter&lt;/code&gt;, we can do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ChonkOMeter do
  @moduledoc File.read!(Path.expand(&amp;quot;./README.md&amp;quot;))
             |&amp;gt; String.split(&amp;quot;&amp;lt;!-- README START --&amp;gt;&amp;quot;)
             |&amp;gt; Enum.at(1)
             |&amp;gt; String.split(&amp;quot;&amp;lt;!-- README END --&amp;gt;&amp;quot;)
             |&amp;gt; List.first()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will extract the guide sandwiched between the markdown comments and set it as the moduledoc. Now we only need to change the README to update both!&lt;/p&gt;
&lt;p&gt;We can generate the documentation and view it locally to verify that this works as expected. If you run &lt;code&gt;mix docs&lt;/code&gt;, a &lt;code&gt;doc&lt;/code&gt; folder will appear with an &lt;code&gt;index.html&lt;/code&gt; file. We can &lt;code&gt;open doc/index.html&lt;/code&gt; to view our documentation in the browser.&lt;/p&gt;
&lt;h2&gt;Adding an Image to the Moduledoc&lt;/h2&gt;
&lt;p&gt;If you navigate to the module&amp;#39;s documentation, you will notice that the image is missing. Hex allows you to point to assets in your docs as long as they are included inside the &lt;code&gt;doc&lt;/code&gt; directory (generated when you create docs with the &lt;code&gt;mix docs&lt;/code&gt; command).&lt;/p&gt;
&lt;p&gt;Usually, that command overwrites the whole &lt;code&gt;doc&lt;/code&gt; folder. So, to ensure that our pictures are always copied there, we can use an alias in our &lt;code&gt;mix.exs&lt;/code&gt; file. We will turn the &lt;code&gt;mix docs&lt;/code&gt; command into one that runs &lt;code&gt;mix docs&lt;/code&gt; and then copies all images inside the &lt;code&gt;/images&lt;/code&gt; directory into a &lt;code&gt;doc/images&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ChonkOMeter.MixProject do
  use Mix.Project

  def project do
    [
      ...
      aliases: aliases(),
      ...
    ]
  end

  defp aliases() do
    [docs: [&amp;quot;docs&amp;quot;, &amp;amp;copy_pictures/1]]
  end

  defp copy_pictures(_) do
    File.cp_r(Path.expand(&amp;quot;./images/&amp;quot;), Path.expand(&amp;quot;./doc/images/&amp;quot;))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you run &lt;code&gt;mix docs&lt;/code&gt; now, you will see that the &lt;code&gt;images/&lt;/code&gt; directory gets copied over to the &lt;code&gt;doc&lt;/code&gt; folder. Open the &lt;code&gt;doc/index.html&lt;/code&gt; file and you should now see the chonk chart appear!&lt;/p&gt;
&lt;h2&gt;Doctests in Elixir&amp;#39;s Livebook&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s important to note that in writing our moduledoc in this way, we don&amp;#39;t lose any of the usual capabilities ex_docs give us.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Anything you can normally do in a doctest, you can still do here. To demonstrate that, let&amp;#39;s add a doctest to our README. First, we&amp;#39;ll need a function to test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ChonkOMeter do
  @moduledoc File.read!(Path.expand(&amp;quot;./README.md&amp;quot;))
             |&amp;gt; String.split(&amp;quot;&amp;lt;!-- README START --&amp;gt;&amp;quot;)
             |&amp;gt; Enum.at(1)
             |&amp;gt; String.split(&amp;quot;&amp;lt;!-- README END --&amp;gt;&amp;quot;)

  @doc &amp;quot;&amp;quot;&amp;quot;
  Returns the Chonk rating for a given number of story points.
  &amp;quot;&amp;quot;&amp;quot;
  def story_points(points) when is_integer(points) and points &amp;gt;= 0 and points &amp;lt; 3 do
    &amp;quot;A Fine Boi&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 3 and points &amp;lt; 5 do
    &amp;quot;He Chomnk&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 5 and points &amp;lt; 8 do
    &amp;quot;A Heckin&amp;#39; Chonker&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 8 and points &amp;lt; 10 do
    &amp;quot;H E F T Y C H O N K&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 10 and points &amp;lt; 15 do
    &amp;quot;Mega Chonk&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 15 do
    &amp;quot;Oh Lawd He Comin&amp;#39;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now remove the boilerplate in our test file, so it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ChonkOMeterTest do
  use ExUnit.Case
  doctest ChonkOMeter
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the tests to ensure there are none for now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mix test
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, in our README, we can add the usual doctest syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;&amp;lt;!-- README START --&amp;gt;

Chonk O Meter is a state-of-the-art size estimator. It will rate the size of anything according to the following chart:

![alt chart showing cats of various sizes](./images/chonk.jpg)

For example:

    iex&amp;gt; ChonkOMeter.story_points(10)
    &amp;quot;Mega Chonk&amp;quot;

&amp;lt;!-- README END --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you run the tests, you will notice that the change in the README has not triggered a re-compilation, meaning the app still thinks there are no doctests. To fix this, we just need to add an &lt;a href=&quot;https://hexdocs.pm/elixir/Module.html#module-external_resource&quot;&gt;&lt;code&gt;@external_resource&lt;/code&gt;&lt;/a&gt; module attribute into the main module. This tells mix to recompile when the README changes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ChonkOMeter do
  @external_resource Path.expand(&amp;quot;./README.md&amp;quot;)
  # ^^ Add this line ^^
  @moduledoc File.read!(Path.expand(&amp;quot;./README.md&amp;quot;))
             |&amp;gt; String.split(&amp;quot;&amp;lt;!-- README START --&amp;gt;&amp;quot;)
             |&amp;gt; Enum.at(1)
             |&amp;gt; String.split(&amp;quot;&amp;lt;!-- README END --&amp;gt;&amp;quot;)

  @doc &amp;quot;&amp;quot;&amp;quot;
  Returns the Chonk rating for a given number of story points.
  &amp;quot;&amp;quot;&amp;quot;
  def story_points(points) when is_integer(points) and points &amp;gt;= 0 and points &amp;lt; 3 do
    &amp;quot;A Fine Boi&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 3 and points &amp;lt; 5 do
    &amp;quot;He Chomnk&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 5 and points &amp;lt; 8 do
    &amp;quot;A Heckin&amp;#39; Chonker&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 8 and points &amp;lt; 10 do
    &amp;quot;H E F T Y C H O N K&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 10 and points &amp;lt; 15 do
    &amp;quot;Mega Chonk&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 15 do
    &amp;quot;Oh Lawd He Comin&amp;#39;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we run our tests, this now results in one passing doctest! We can also add a doctest to our function doc like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...
  @doc &amp;quot;&amp;quot;&amp;quot;
  Returns the Chonk rating for a given number of story points.

      iex&amp;gt; ChonkOMeter.story_points(5)
      &amp;quot;A Heckin&amp;#39; Chonker&amp;quot;
  &amp;quot;&amp;quot;&amp;quot;
  def story_points(points) when is_integer(points) and points &amp;gt;= 0 and points &amp;lt; 3 do
    &amp;quot;A Fine Boi&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 3 and points &amp;lt; 5 do
    &amp;quot;He Chomnk&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 5 and points &amp;lt; 8 do
    &amp;quot;A Heckin&amp;#39; Chonker&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 8 and points &amp;lt; 10 do
    &amp;quot;H E F T Y C H O N K&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 10 and points &amp;lt; 15 do
    &amp;quot;Mega Chonk&amp;quot;
  end

  def story_points(points) when is_integer(points) and points &amp;gt;= 15 do
    &amp;quot;Oh Lawd He Comin&amp;#39;&amp;quot;
  end
...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Adding Livebook to Elixir&lt;/h2&gt;
&lt;p&gt;So let&amp;#39;s recap. Right now, we have a README as the source of truth for our moduledoc. We can have doctests and images and all the usual goodies that a moduledoc is allowed, but we don&amp;#39;t have to repeat ourselves and risk copy/paste errors.&lt;/p&gt;
&lt;p&gt;We want to keep that same energy going for our Livebook, to avoid repeating ourselves manually, but still have an interactive playground for our library on top of the usual moduledocs.&lt;/p&gt;
&lt;p&gt;To do that, we can generate our Livebook from our module. To help with this, I&amp;#39;ve written a library we can include called &lt;a href=&quot;https://github.com/Adzz/livebook_helpers&quot;&gt;livebook_helpers&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:ex_doc, &amp;quot;&amp;gt;= 0.0.0&amp;quot;, runtime: false, only: [:docs, :dev]},
    {:livebook_helpers, &amp;quot;&amp;gt;= 0.0.0&amp;quot;, only: [:docs, :dev]},
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once we have fetched the deps with &lt;code&gt;mix deps.get&lt;/code&gt;, running &lt;code&gt;mix help&lt;/code&gt; shows one extra mix task:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;...
mix create_livebook_from_module # Creates a livebook from the docs in the given module.
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see from &lt;a href=&quot;https://hexdocs.pm/livebook_helpers/Mix.Tasks.CreateLivebookFromModule.html&quot;&gt;the docs&lt;/a&gt; that we run the mix task by providing a module and a path to a Livebook. Let&amp;#39;s try that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mix create_livebook_from_module ChonkOMeter &amp;quot;chonk_o_meter_introduction&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should see a successful output that links to the generated Livebook! 🎉 There is one last thing we can do to make our workflow seamless. Let&amp;#39;s add &lt;code&gt;create_livebook_from_module&lt;/code&gt; to the end of the &lt;code&gt;mix docs&lt;/code&gt; command.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ChonkOMeter.MixProject do
  use Mix.Project

  def project do
    [
      ...
      aliases: aliases(),
      ...
    ]
  end

  defp aliases() do
    [docs: [&amp;quot;docs&amp;quot;, &amp;amp;copy_pictures/1, &amp;amp;create_livebook/1]]
  end

  defp copy_pictures(_) do
    File.cp_r(Path.expand(&amp;quot;./images/&amp;quot;), Path.expand(&amp;quot;./doc/images/&amp;quot;))
  end

  defp create_livebook(_) do
    Mix.Task.run(&amp;quot;create_livebook_from_module&amp;quot;, [&amp;quot;ChonkOMeter&amp;quot;, &amp;quot;chonk_o_meter_introduction&amp;quot;])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whenever we run &lt;code&gt;mix docs&lt;/code&gt;, we will copy over any static images used in the README and generate a Livebook from our main module!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-05/livebook.png&quot; alt=&quot;alt picture of the generated livebook showing the same moduledocs&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Running Livebook in Elixir&lt;/h2&gt;
&lt;p&gt;So far, so good! We have a nice pipeline to create a useful Livebook, but now we need to think about running the Livebook. Start the Livebook app like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;livebook server
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, the Elixir sections only have access to the Elixir and Erlang standard library. If we run our generated library and then attempt to run an Elixir cell that calls the library, it will fail because the library code is not there. To solve this, we have two options — &lt;code&gt;Mix.install&lt;/code&gt; or Livebook runtime.&lt;/p&gt;
&lt;h3&gt;Add &lt;code&gt;Mix.install&lt;/code&gt; to Livebook&lt;/h3&gt;
&lt;p&gt;We could add a section to the beginning of the Livebook that does this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Mix.install([:chonk_o_meter])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-05/mix_install.png&quot; alt=&quot;alt text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;When called, we will get the latest version of the library from Hex. It will be made available to all subsequent Elixir cells, just like when you run &lt;code&gt;Mix.install&lt;/code&gt; inside an IEx REPL.&lt;/p&gt;
&lt;p&gt;You can also easily specify a version and provide live documentation for any version of a given library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Mix.install([{chonk_o_meter: &amp;quot;&amp;gt;=0.0.1&amp;quot;}])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;LivebookHelpers&lt;/code&gt; can even generate a Livebook with a &lt;code&gt;Mix.install&lt;/code&gt; at the beginning if we supply deps to the mix task:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;mix create_livebook_from_module ChonkOMeter &amp;quot;chonk_o_meter_introduction&amp;quot; &amp;quot;[:chonk_o_meter&amp;quot;]&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works great for any library that is deployed to Hex. However, you&amp;#39;ll run into problems if, for example, you want a Livebook for a &lt;code&gt;main&lt;/code&gt; branch. In that case, you can do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Mix.install [{:chonk_o_meter, path: &amp;quot;./&amp;quot;}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tells mix to look in the provided path for a local version of the library. This, of course, makes some assumptions about &lt;em&gt;where&lt;/em&gt; the Livebook will run, so it&amp;#39;s good to make that clear. If you put the Livebook at the root of the repo and a user starts the Livebook server from there, then the path &lt;code&gt;&amp;quot;./&amp;quot;&lt;/code&gt; will work.&lt;/p&gt;
&lt;p&gt;If you don&amp;#39;t want to rely on this, though, Livebook has your back with a powerful feature: runtime!&lt;/p&gt;
&lt;h3&gt;Livebook Runtime&lt;/h3&gt;
&lt;p&gt;There are three kinds of runtime, but they all let you point to code and call it in any Elixir cell within your Livebook.&lt;/p&gt;
&lt;p&gt;The three runtime options are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Embedded&lt;/li&gt;
&lt;li&gt;Attached node&lt;/li&gt;
&lt;li&gt;Mix standalone&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You select the runtime by clicking the cog symbol here:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-05/runtime.png&quot; alt=&quot;alt text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at each runtime option below.&lt;/p&gt;
&lt;h3&gt;Embedded Mode&lt;/h3&gt;
&lt;p&gt;Embedded Mode lets us run the notebook code within the Livebook node itself! This is really for specific cases where there is no option to start a separate Elixir runtime — for example, on embedded devices.&lt;/p&gt;
&lt;p&gt;Code defined in one notebook may interfere with code from another notebook. So this mode should only be used if you have no alternative and is not relevant here.&lt;/p&gt;
&lt;h3&gt;Attached Node&lt;/h3&gt;
&lt;p&gt;The attached node runtime connects a Livebook to a running Elixir app via the usual Erlang magic that we use to connect two running nodes. It looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-05/attached.png&quot; alt=&quot;alt attached node option&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As long as the app starts with a cookie that you know and a &lt;code&gt;sname&lt;/code&gt;, you can give them to Livebook and connect. This is like getting a remote shell in a running app but with a more full-featured text-editing environment.&lt;/p&gt;
&lt;p&gt;Using an attached node gives you complete control over how your app starts. You get much more control than the mix standalone and can do all sorts of things, like set env vars and start other services (like a database).&lt;/p&gt;
&lt;p&gt;An attached node could be especially relevant for creating internal (live!) documentation for closed-source repos at work, but is not relevant for us and our library.&lt;/p&gt;
&lt;h3&gt;Mix Standalone&lt;/h3&gt;
&lt;p&gt;Finally, the Mix standalone runtime lets you point to a mix project which Livebook will compile and start (analogous to running &lt;code&gt;iex -S mix&lt;/code&gt; in your terminal).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-05/standalone.png&quot; alt=&quot;alt mix standalone option&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Mix standalone confers a great advantage over &lt;code&gt;Mix.install&lt;/code&gt;, as you can recompile it! It&amp;#39;s useful if you write a Livebook from scratch; in that case, you&amp;#39;ll likely add something to the library that you&amp;#39;ll then want to use in the Livebook.&lt;/p&gt;
&lt;p&gt;Instead of having to kill the Livebook server and restart to access the new functions, you can add an Elixir cell with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;IEx.Helpers.recompile()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will recompile the connected mix app (i.e., our library) when you call it, meaning you get access to any new functionality therein.&lt;/p&gt;
&lt;h2&gt;Livebook for Docs: Try It Yourself in Your Elixir App&lt;/h2&gt;
&lt;p&gt;That concludes our tour of Livebook for docs. You can &lt;a href=&quot;https://github.com/Adzz/chonk_o_meter&quot;&gt;see the &lt;code&gt;chonk_o_meter&lt;/code&gt; library example here&lt;/a&gt;. For an example of these ideas in action in a real library, &lt;a href=&quot;https://Github.com/Adzz/data_schema/blob/main/lib/data_schema.ex#L2&quot;&gt;check out my data_schema library&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;Currently, GitHub doesn&amp;#39;t recognize the &lt;code&gt;.livemd&lt;/code&gt; extension, so if you play around with Livebook, I would encourage you to push to public repos. The more we do this, the more chance we have of getting GitHub to parse the files with nice syntax highlighting and markdown rendering.&lt;/p&gt;
&lt;p&gt;Until that happens, though, we can put a magic line at the top of a Livebook to force GitHub to render it as markdown:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;&amp;lt;!-- vim: syntax=markdown --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Livebook that &lt;a href=&quot;https://Github.com/Adzz/livebook_helpers&quot;&gt;Livebook helpers&lt;/a&gt; generates will include this line for you. Now you have all the knowledge you need go forth and create live docs!&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Guide to Event-Driven Architecture in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/05/10/a-guide-to-event-driven-architecture-in-elixir.html"/>
    <id>https://blog.appsignal.com/2022/05/10/a-guide-to-event-driven-architecture-in-elixir.html</id>
    <published>2022-05-10T00:00:00+00:00</published>
    <updated>2022-05-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s explore three ways to implement event-driven architecture in Elixir — synchronously, using GenServer, and using GenStage.</summary>
    <content type="html">&lt;p&gt;In this post, we will explore how event-driven architecture can make your app more responsive for users and decouple your modules for a better developer experience.&lt;/p&gt;
&lt;p&gt;We will also look at several methods of implementing event-driven architecture with Elixir.
Elixir is particularly good for this because of the advanced and concise message-passing APIs that it offers and BEAM&amp;#39;s outstanding support for concurrency.&lt;/p&gt;
&lt;p&gt;But first: what is event-driven architecture, exactly?&lt;/p&gt;
&lt;h2&gt;Event-Driven Architecture: An Introduction&lt;/h2&gt;
&lt;p&gt;Event-driven architecture is an architecture where events control the behavior and flow of your application.
The main components of the architecture are event producers, event bus, and event consumers.&lt;/p&gt;
&lt;p&gt;An event could be anything that represents a change of state in the system.
For example, in an e-commerce application, the purchase of a product by the user could produce a &lt;code&gt;sold&lt;/code&gt; event which the consumer can then process to update inventory.&lt;/p&gt;
&lt;p&gt;An event-based architecture allows applications to act on events as they occur.
Different parts of an application work and develop relatively independently in well-crafted event-based design. Organizations can assign separate teams to focused parts of the application and streamline the workflow.
This also creates a clear boundary between different parts of an application, assisting in future scalability exercises.&lt;/p&gt;
&lt;p&gt;Event-driven architecture has mainly gained popularity with microservice-based products but can also be used for a monolith.&lt;/p&gt;
&lt;p&gt;Things are always clearer with an example, so let&amp;#39;s look at one.&lt;/p&gt;
&lt;h2&gt;Building Blocks of Event-Driven Architecture&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s discuss each building block in detail, using an e-commerce application as an example.&lt;/p&gt;
&lt;p&gt;Imagine that a user makes a new purchase on a website.
The &lt;code&gt;new order&lt;/code&gt; is an event generated by the part that controls the ordering: the &lt;strong&gt;event producer&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The event can be pushed onto an &lt;strong&gt;event bus&lt;/strong&gt;.
The event bus could be anything, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A table in the database.&lt;/li&gt;
&lt;li&gt;An in-memory event queue inside the app.&lt;/li&gt;
&lt;li&gt;An external tool like RabbitMQ or Apache Kafka.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;event consumers&lt;/strong&gt; interested in this type of event can subscribe to the event bus. The event is delivered to them, and they do some processing on top of it.&lt;/p&gt;
&lt;p&gt;For example, an inventory management system would subscribe to the &lt;code&gt;new order&lt;/code&gt; event and update the inventory of the product.
Another system could also pick the same event in the application — for example, a fulfillment service might process that event and create a delivery route for the product.&lt;/p&gt;
&lt;h2&gt;Benefits of Event-Driven Architecture&lt;/h2&gt;
&lt;p&gt;There are several advantages of using an event-driven architecture instead of one that processes everything sequentially.&lt;/p&gt;
&lt;p&gt;An event-driven architecture allows us to build several independent parts of an application to work off the same event and do different focused tasks.
This can be advantageous for a couple of reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One team needs to focus on only one part.&lt;/li&gt;
&lt;li&gt;The application code for small parts can be simple.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another advantage of the design is that it allows us to deliver a snappy interface to the user.
As an example from the above application, a user needs to make an order.
The application can continue processing all other non-interactive tasks, like updating its inventory and interacting with
the delivery application, without the user&amp;#39;s attention.&lt;/p&gt;
&lt;p&gt;This also makes adding new processing steps in the event pipeline very easy. For example, let&amp;#39;s say we need an additional task to be performed from an event. We only need to add a new consumer to handle the event, without touching any other parts of the application.&lt;/p&gt;
&lt;p&gt;Finally, it is much easier to scale each individual module if it is decoupled from the others, than to scale a whole application together.
This is even more beneficial when you have a part that takes much more resources than its counterparts in the event processing pipeline.&lt;/p&gt;
&lt;p&gt;But event-driven architecture does not come without disadvantages when not properly thought out.
If applied to very simple problems, it can lead to complex workflows that are slow and difficult to debug.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s explore some simple ways event-driven architecture can be implemented with Elixir, without the need to write complex pieces of code.&lt;/p&gt;
&lt;h2&gt;Synchronous Event-Driven Architecture in Elixir&lt;/h2&gt;
&lt;p&gt;The simplest (and most inefficient) way to run the above flow would be to do everything synchronously in the user request.&lt;/p&gt;
&lt;p&gt;So, if you have an &lt;code&gt;Orders&lt;/code&gt; module that processes a user&amp;#39;s order request, the synchronous implementation could look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Orders do
  def create_order(attrs) do
    {:ok, order} = save_order(attrs)
    {:ok, _inventory} = update_inventory(order)
    {:ok, _delivery} = create_delivery(order)
    {:ok, order}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;We can improve this to more easily scale for new event consumers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Orders do
  @event_consumers [
    {Inventory, :handle_event},
    {Delivery, :handle_event},
  ]

  def create_order(attrs) do
    {:ok, order} = save_order(attrs)

    event = %Orders.Event{type: :new_order, payload: order}
    @event_consumers
    |&amp;gt; Enum.each(fn {module, func} -&amp;gt;
      apply(module, func, [event])
    end)

    {:ok, order}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this implementation, all we need to do to add new consumers is to add the specification in the &lt;code&gt;@event_consumers&lt;/code&gt; array, and those consumers can work independently.&lt;/p&gt;
&lt;p&gt;While the synchronous approach works well for a small number of consumers, it has a disadvantage. Creating an order might take a long time because you will need to wait for the inventory to update and the delivery to be created.&lt;/p&gt;
&lt;p&gt;These are all internal tasks that can be performed without user interaction and moved from the synchronous chain.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see how we can further streamline event-driven architecture using &lt;code&gt;GenServer&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Using GenServer for Event-Driven Architecture in Elixir&lt;/h2&gt;
&lt;p&gt;For this implementation, we will run a separate process for each consumer.
These will subscribe to an event from a producer and run their tasks concurrently.&lt;/p&gt;
&lt;p&gt;For the event bus, we can use &lt;a href=&quot;https://hexdocs.pm/phoenix_pubsub/Phoenix.PubSub.html&quot;&gt;&lt;code&gt;Phoenix.PubSub&lt;/code&gt;&lt;/a&gt;.
Note that it is possible for apps that don&amp;#39;t use Phoenix to directly &lt;a href=&quot;https://hexdocs.pm/elixir/Registry.html#module-using-as-a-pubsub&quot;&gt;use Registry as a PubSub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s look at the producer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Orders do
  def create_order(attrs) do
    {:ok, order} = save_order(attrs)
    event = %Orders.Event{type: :new_order, payload: order}
    Phoenix.PubSub.broadcast(:my_app, &amp;quot;new_order&amp;quot;, event)
    {:ok, order}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a new order, we create the event struct and use &lt;code&gt;Phoenix.PubSub.broadcast/3&lt;/code&gt; to broadcast that event on the bus.
As you can see, it is much simpler than the previous implementation where the &lt;code&gt;Orders&lt;/code&gt; module processed tasks from the other module serially.&lt;/p&gt;
&lt;p&gt;The consumers can then subscribe to the &lt;code&gt;new_order&lt;/code&gt; topic and implement the &lt;code&gt;handle_info/2&lt;/code&gt; to be notified every time a new event is published by the producer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Inventory do
  use GenServer

  def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)

  def init(_opts) do
    Phoenix.PubSub.subscribe(:my_app, &amp;quot;new_order&amp;quot;)
  end

  def handle_info(%Orders.Event{type: :new_order, payload: order}, state) do
    state = consume(state, order.product)
    {:noreply, state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Delivery&lt;/code&gt; module will be very similar to the above, so I am skipping it here.&lt;/p&gt;
&lt;p&gt;As you can see, this is much better than the previous implementations.
&lt;code&gt;Inventory&lt;/code&gt; and &lt;code&gt;Delivery&lt;/code&gt; modules can independently subscribe to the &lt;code&gt;new_order&lt;/code&gt; topic.
The &lt;code&gt;Orders&lt;/code&gt; module broadcasts to this topic on new orders and events are delivered to the subscribed processes.&lt;/p&gt;
&lt;p&gt;You could even distribute this between multiple nodes and &lt;code&gt;Phoenix.PubSub&lt;/code&gt; (with a PG, Redis, or other adapter), spreading the events to all nodes.&lt;/p&gt;
&lt;p&gt;Great, right? Not really.
There are several issues with this approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PubSub provides a real-time broadcast without message queueing, so if one of the subscriber processes is down, it might miss the broadcasts.&lt;/li&gt;
&lt;li&gt;If the subscriber does some heavy work, it might not be able to keep up with the incoming messages, resulting in timeouts and consequently crashing the process tree.&lt;/li&gt;
&lt;li&gt;If the subscriber experiences an error when processing a message, it is considered consumed and won&amp;#39;t be retried later.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So this approach is a bad one to follow for our current use case.&lt;/p&gt;
&lt;p&gt;However, the approach still has its use cases. It can be used for tasks that aren&amp;#39;t critical, or that can be corrected with the next message: for example, if a task computes the suggestions for a user&amp;#39;s next purchases based on their last purchase.
While this would also need to be triggered on a new order, it isn&amp;#39;t exactly critical (for a traditional e-commerce website) and can re-compute suggestions for a user on their next purchase.&lt;/p&gt;
&lt;h2&gt;Event-Driven Implementation Using GenStage in Elixir&lt;/h2&gt;
&lt;p&gt;In the previous section, we saw a great implementation of our event-driven system using GenServer.
But it didn&amp;#39;t come without its limitations.
Let&amp;#39;s see how &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.html&quot;&gt;GenStage&lt;/a&gt; fares.&lt;/p&gt;
&lt;p&gt;GenStage makes a clear distinction between &lt;code&gt;producers&lt;/code&gt;, &lt;code&gt;consumers&lt;/code&gt;, and &lt;code&gt;producer_consumers&lt;/code&gt;, and each process has to pick one when it starts (in its &lt;code&gt;init/1&lt;/code&gt;).
In our case, both &lt;code&gt;Inventory&lt;/code&gt; and &lt;code&gt;Deliver&lt;/code&gt; are &lt;code&gt;consumers&lt;/code&gt;, and &lt;code&gt;Orders&lt;/code&gt; is a producer.&lt;/p&gt;
&lt;p&gt;This is where things start to get a little complicated.
&lt;code&gt;GenStage&lt;/code&gt; has a concept of &lt;em&gt;demand&lt;/em&gt;.
Each &lt;code&gt;consumer&lt;/code&gt; can issue a &lt;em&gt;demand&lt;/em&gt; of how many events it can handle. The &lt;code&gt;producer&lt;/code&gt; needs to send those events to the consumer.
Let&amp;#39;s see a basic &lt;code&gt;producer&lt;/code&gt; in action.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Orders do
  use GenStage

  def start_link(opts) do
    GenStage.start_link(__MODULE__, opts, name: __MODULE__)
  end

  def init(_opts) do
    {:producer, :some_state_which_does_not_currently_mattere}
  end

  def create_order(pid, attrs) do
    GenStage.cast(pid, {:create_order, attrs})
  end

  def handle_cast({:create_order, attrs}, state) do
    {:ok, order} = save_order(attrs)
    {:noreply, [%Orders.Event{type: new_order, payload: order}], state}
  end

  def handle_demand(_demand, state), do: {:noreply, [], state}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The meat of our code is in &lt;code&gt;handle_cast&lt;/code&gt;, where we save the order and return a tuple like &lt;code&gt;{:noreply, events, new_state}&lt;/code&gt;.
The new events are stored in an internal &lt;code&gt;GenStage&lt;/code&gt; buffer and dispatched to the consumers as they make new demands (or immediately, if there are consumers with unmet demand).&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s check out a sample implementation of the &lt;code&gt;consumer&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Inventory do
  use GenStage

  def start_link(opts) do
    GenStage.start_link(__MODULE__, opts, name: __MODULE__)
  end

  def init(_opts) do
    {:consumer, [], subscribe_to: [Orders]}
  end

  def handle_events(events, _from, state) do
    state = Enum.reduce(events, state, &amp;amp; handle_event(&amp;amp;1, &amp;amp;2))
    {:noreply, [], state}
  end

  def handle_event(%Orders.Event{type: :new_order, payload: order}, state) do
    new_state = update_inventory(order)
    new_state
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the consumer, first notice that we have a &lt;code&gt;subscribe_to&lt;/code&gt; inside &lt;code&gt;init/1&lt;/code&gt;.
This automatically subscribes &lt;code&gt;Inventory&lt;/code&gt; to any events published by &lt;code&gt;Orders&lt;/code&gt;.
Please check the &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.html#c:init/1&quot;&gt;GenStage documentation for additional options available in init&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here, most of the work happens inside &lt;code&gt;handle_events/3&lt;/code&gt;, which is automatically called by &lt;code&gt;GenStage&lt;/code&gt; as soon as new events become available.
We handle the &lt;code&gt;new_order&lt;/code&gt; event here, updating the inventory and returning a new state.&lt;/p&gt;
&lt;p&gt;With this simple implementation, we get several benefits that outpace the GenServer implementation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Automatic buffering of events inside GenStage&amp;#39;s internal buffer when the producer has new events without any available consumer.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even if consumers are down when some events are produced, we are still guaranteed to receive them when the consumer comes back up.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.html#module-buffering-demand&quot;&gt;Check out Genstage&amp;#39;s guide on buffering demand&lt;/a&gt; for advanced buffering logic.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Automatic distribution of work on multiple consumers.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you have heavy consumer tasks, you can start multiple consumer processes. The default &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.DemandDispatcher.html&quot;&gt;&lt;code&gt;DemandDispatcher&lt;/code&gt;&lt;/a&gt; for GenStage will distribute the work evenly across all processes.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.Dispatcher.html&quot;&gt;GenStage.Dispatcher&lt;/a&gt; for other dispatch strategies to &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.BroadcastDispatcher.html&quot;&gt;distribute events to all consumers&lt;/a&gt; or &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.PartitionDispatcher.html&quot;&gt;partition distribution to consumers based on a hash function&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But, as with GenServer or synchronous implementation, using GenStage does not come without its problems.&lt;/p&gt;
&lt;p&gt;If a consumer crashes while it is processing an event, GenStage will consider the event delivered and will not send it again when the consumer comes back up.&lt;/p&gt;
&lt;p&gt;To make sure that you properly track crashes, you can use a monitoring service &lt;a href=&quot;https://www.appsignal.com/&quot;&gt;like AppSignal&lt;/a&gt;. AppSignal is &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;easy to install for your Elixir app&lt;/a&gt; and helps you monitor performance as well as &lt;a href=&quot;https://www.appsignal.com/tour/errors&quot;&gt;track errors&lt;/a&gt;. Here&amp;#39;s an example of an error tracking dashboard that AppSignal provides:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-05/errors-appsignal.png&quot; alt=&quot;AppSignal Errors Screenshot&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can set up notifications for crashes via AppSignal as well.&lt;/p&gt;
&lt;p&gt;On the app side, you can cache such events in a persistent store once they are delivered to the consumer. If the consumer crashes, then once it recovers, it can revert to the cached events.&lt;/p&gt;
&lt;p&gt;Be very cautious about producing too many events without enough consumers, though.
While GenStage offers automatic buffering of events, this buffer has a (configurable) maximum size and a practical maximum size constrained by the server&amp;#39;s memory.&lt;/p&gt;
&lt;p&gt;If you don&amp;#39;t control the frequency with which events are produced, consider using an external data store like Redis or Postgres to buffer events.&lt;/p&gt;
&lt;h2&gt;Wrap Up: Event-Driven Architecture in Elixir — Going Beyond GenStage&lt;/h2&gt;
&lt;p&gt;In this post, we examined three approaches to implementing an event-driven system in Elixir: synchronously, using GenServer, and finally, using GenStage. We took a look at some of the advantages and disadvantages of each approach.&lt;/p&gt;
&lt;p&gt;The simple &lt;code&gt;GenStage&lt;/code&gt; example can be a starting point for implementing complex event-driven data processing pipelines that span multiple nodes.
I suggest you &lt;a href=&quot;https://hexdocs.pm/gen_stage/GenStage.html&quot;&gt;read the great GenStage documentation for more information&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are looking for an even higher-level abstraction, &lt;a href=&quot;https://elixir-broadway.org/&quot;&gt;Broadway&lt;/a&gt; is a good starting point.
It is built on top of GenStage and offers several additional features, including consuming data from external queues like Amazon SQS, Apache Kafka, and RabbitMQ.&lt;/p&gt;
&lt;p&gt;Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Using Profiling in Elixir to Improve Performance</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/04/26/using-profiling-in-elixir-to-improve-performance.html"/>
    <id>https://blog.appsignal.com/2022/04/26/using-profiling-in-elixir-to-improve-performance.html</id>
    <published>2022-04-26T00:00:00+00:00</published>
    <updated>2022-04-26T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s explore three profiling tools you can use to find performance issues in Elixir — `cprof`, `eprof`, and `fprof`.</summary>
    <content type="html">&lt;p&gt;Elixir is all about performance.
Say you have an app up and running with Elixir, but some parts aren&amp;#39;t working as fast as you would like them to.&lt;/p&gt;
&lt;p&gt;That is where profiling comes in.
Profiling tools usually walk you through the frequency and duration of function calls and where they spend their time.
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;&amp;#39;premature optimization is the root of all evil.&amp;#39;&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&amp;#39;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.
It doesn&amp;#39;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&amp;#39; runtimes. You&amp;#39;ll see the frequency with which each function is invoked.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;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=&quot;https://gist.github.com/pulkit110/c8223b7ebf4dc6cb918f440c45e201cd&quot;&gt;follow along with the code&lt;/a&gt;.
It uses the &lt;a href=&quot;https://rosettacode.org/wiki/Fibonacci_sequence#Elixir&quot;&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(15)&amp;gt; :cprof.start()
19244
iex(16)&amp;gt; FibonacciRosettaCode.list(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
iex(17)&amp;gt; :cprof.analyse(FibonacciRosettaCode)
{FibonacciRosettaCode, 79,
 [
   {{FibonacciRosettaCode, :fibonacci, 3}, 54},
   {{FibonacciRosettaCode, :fibonacci, 1}, 11},
   {{FibonacciRosettaCode, :&amp;quot;-fun.fibonacci/1-&amp;quot;, 1}, 11},
   {{FibonacciRosettaCode, :module_info, 1}, 1},
   {{FibonacciRosettaCode, :list, 1}, 1},
   {{FibonacciRosettaCode, :__info__, 1}, 1}
 ]}
iex(18)&amp;gt; :cprof.stop()
19266
&lt;/code&gt;&lt;/pre&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=&quot;https://www.erlang.org/doc/man/cprof.html&quot;&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&amp;#39;s wrapper task &lt;a href=&quot;https://hexdocs.pm/mix/1.12/Mix.Tasks.Profile.Cprof.html&quot;&gt;profile.cprof&lt;/a&gt; directly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;➜ mix profile.cprof -e &amp;quot;FibonacciRosettaCode.list(10)&amp;quot;
                                                                     CNT
Total                                                                113
FibonacciRosettaCode                                                  77  &amp;lt;--
  FibonacciRosettaCode.fibonacci/3                                    54
  FibonacciRosettaCode.fibonacci/1                                    11
  FibonacciRosettaCode.&amp;quot;-fun.fibonacci/1-&amp;quot;/1                          11
  FibonacciRosettaCode.list/1                                          1
Enum                                                                  24  &amp;lt;--
  Enum.reduce_range/5                                                 12
  anonymous fn/3 in Enum.map/2                                        11
  Enum.map/2                                                           1
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we can see that the function &lt;code&gt;fibonacci/3&lt;/code&gt; is called the most.
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;Banner lang=&quot;elixir&quot; /&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.
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&amp;#39;s analyze the results from the mix task &lt;a href=&quot;https://hexdocs.pm/mix/1.12/Mix.Tasks.Profile.Eprof.html&quot;&gt;&lt;code&gt;profile.eprof&lt;/code&gt;&lt;/a&gt; on our sample Fibonacci generator.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;➜ mix profile.eprof -e &amp;quot;FibonacciRosettaCode.list(10)&amp;quot;
#                                               CALLS     % TIME µS/CALL
Total                                             106 100.0   45    0.42
anonymous fn/0 in :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.&amp;quot;-fun.fibonacci/1-&amp;quot;/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 in 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;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.
The usage is very simple. Let&amp;#39;s see an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;:eprof.start_profiling([self()])

# Do some work
1..100 |&amp;gt; Enum.each(fn i -&amp;gt;
  spawn(fn -&amp;gt; FibonacciRosettaCode.list(i + 1) end)
end)

:eprof.stop_profiling()
:eprof.analyze()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You need to call &lt;code&gt;start_profiling/1&lt;/code&gt; with a list of processes to profile.
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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;****** Process &amp;lt;0.150.0&amp;gt;    -- 37.26 % of profiled time ***
FUNCTION                                                             CALLS        %   TIME  [uS / CALLS]
--------                                                             -----  -------   ----  [----------]
io:request/2                                                             3     0.00      0  [      0.00]
...

****** Process &amp;lt;0.277.0&amp;gt;    -- 0.05 % of profiled time ***
FUNCTION                                             CALLS        %  TIME  [uS / CALLS]
--------                                             -----  -------  ----  [----------]
&amp;#39;Elixir.FibonacciRosettaCode&amp;#39;:fibonacci/3                2     0.00     0  [      0.00]
&amp;#39;Elixir.FibonacciRosettaCode&amp;#39;:fibonacci/1                3     3.03     1  [      0.33]
&amp;#39;Elixir.FibonacciRosettaCode&amp;#39;:&amp;#39;-fun.fibonacci/1-&amp;#39;/1      3     3.03     1  [      0.33]
...
&lt;/code&gt;&lt;/pre&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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;:fprof.start()
:fprof.trace([:start, procs: :all])

# Do some work
1..100 |&amp;gt; Enum.each(fn i -&amp;gt;
  spawn(fn -&amp;gt; FibonacciRosettaCode.list(i + 1) end)
end)

:fprof.trace(:stop)
:fprof.profile()
:fprof.analyse(totals: false, dest: &amp;#39;prof.analysis&amp;#39;)
&lt;/code&gt;&lt;/pre&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=&quot;https://gist.github.com/pulkit110/10ad017e52ad25c6b0ad36199544fd8f&quot;&gt;Here&amp;#39;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.
A popular one is &lt;a href=&quot;https://github.com/isacssouza/erlgrind&quot;&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=&quot;https://kcachegrind.github.io/html/Home.html&quot;&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;.
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;img src=&quot;/images/blog/2022-04/cgrind.png&quot; alt=&quot;qcachegrind graph&quot;/&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=&quot;https://github.com/phoenixframework/phoenix_live_dashboard&quot;&gt;Phoenix&amp;#39;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;img src=&quot;/images/blog/2022-04/phoenix-live-dashboard.png&quot; alt=&quot;Phoenix Live Dashboard Screenshot&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;AppSignal&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://appsignal.com/&quot;&gt;AppSignal&lt;/a&gt; is another great tool for collecting performance data (among other things).
&lt;a href=&quot;https://docs.appsignal.com/elixir/installation/#installing-the-package&quot;&gt;Adding AppSignal to an existing application&lt;/a&gt; takes a few seconds.
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=&quot;https://docs.appsignal.com/elixir/instrumentation/minutely-probes.html&quot;&gt;minutely probes&lt;/a&gt; to track custom metrics.
Here&amp;#39;s an example of the AppSignal dashboard collecting data from a sample application:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-04/appsignal.png&quot; alt=&quot;AppSignal Screenshot&quot;/&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&amp;#39;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;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.PageController do
  use MyApp, :controller

  def index(conn, _params) do
    custom_function()
    render(conn, &amp;quot;index.html&amp;quot;)
  end

  defp custom_function do
    Appsignal.instrument(&amp;quot;custom_function&amp;quot;, fn -&amp;gt;
      :timer.sleep(1000)
    end)
  end
end
&lt;/code&gt;&lt;/pre&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=&quot;https://docs.appsignal.com/elixir/&quot;&gt;the AppSignal docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Wrap-up: Measure Your Elixir App&amp;#39;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&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Phoenix LiveView Under The Hood: The Form Function Component</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/03/29/phoenix-liveview-under-the-hood-the-form-function-component.html"/>
    <id>https://blog.appsignal.com/2022/03/29/phoenix-liveview-under-the-hood-the-form-function-component.html</id>
    <published>2022-03-29T00:00:00+00:00</published>
    <updated>2022-03-29T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s demystify LiveView&#039;s form function component by taking a look under the hood.</summary>
    <content type="html">&lt;p&gt;Thanks to HEEx and function components, LiveView provides developers with a sleek, ergonomic syntax for building and maintaining sophisticated interactive UIs. LiveView&amp;#39;s &lt;code&gt;form/1&lt;/code&gt; function component is a great example of this, making it easier than ever before to render complex forms within LiveView.&lt;/p&gt;
&lt;p&gt;However, the &lt;code&gt;form/1&lt;/code&gt; function component can feel a little mysterious to anyone unfamiliar with LiveView&amp;#39;s function components.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll look under the hood of the &lt;code&gt;form/1&lt;/code&gt; function component. We&amp;#39;ll dive into the Phoenix Component functionality that underpins this function and explore features like component slots. When we&amp;#39;re done, you&amp;#39;ll know exactly how the &lt;code&gt;form/1&lt;/code&gt; function renders your forms and you&amp;#39;ll have a deeper understanding of LiveView components, setting you up to build your own components in the future.&lt;/p&gt;
&lt;h2&gt;What Are Function Components in Phoenix LiveView?&lt;/h2&gt;
&lt;p&gt;Before we dive into the &lt;code&gt;form/1&lt;/code&gt; function component, let&amp;#39;s discuss LiveView&amp;#39;s function components at a high level. Function components are defined in modules that use the &lt;code&gt;Phoenix.Component&lt;/code&gt; behavior. Any function that takes in an argument of assigns and returns some markup wrapped in a HEEx template is a function component.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at a simple example. We&amp;#39;ll define a &lt;code&gt;UserDetails&lt;/code&gt; module that implements a function component, &lt;code&gt;contact_info&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppLive.UserDetails do
  use Phoenix.Component

  def contact_info(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;div class=&amp;quot;contact-info&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Phone:&amp;lt;/strong&amp;gt;&amp;lt;%= @user.phone_number %&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Email:&amp;lt;/strong&amp;gt;&amp;lt;%= @user.email %&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can call on this component with any HEEx template like this (assuming you have an available &lt;code&gt;@current_user&lt;/code&gt; assigns):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;UserDetails.contact_info user=&amp;quot;{@current_user}&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you import the &lt;code&gt;UserDetails&lt;/code&gt; module or if you&amp;#39;re calling on this function component somewhere where the function is defined locally (i.e., elsewhere in the &lt;code&gt;UserDetails&lt;/code&gt; module), you can leave off the module name from the function call:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;.contact_info user={@current_user}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this basic understanding of function components under your belt, we&amp;#39;re ready to dive into the &lt;code&gt;.form/1&lt;/code&gt; function component that LiveView makes available to you. We&amp;#39;ll take a look at some more advanced features of function components along the way.&lt;/p&gt;
&lt;h2&gt;Calling the &lt;code&gt;form/1&lt;/code&gt; Function Component&lt;/h2&gt;
&lt;p&gt;LiveView implements a function component, &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Helpers.html#form/1&quot;&gt;&lt;code&gt;form/1&lt;/code&gt;&lt;/a&gt;. This function component is defined in &lt;code&gt;Phoenix.LiveView.Helper&lt;/code&gt; and imported into all of your live views. We&amp;#39;ll start with the entry point of the &lt;code&gt;form/1&lt;/code&gt; code flow—the caller.&lt;/p&gt;
&lt;p&gt;In this example, we&amp;#39;ll construct a form for a book record that has a title, description, and author, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;.form
    let={f}
    for={@changeset}
    id=&amp;quot;book-form&amp;quot;
    phx-change=&amp;quot;validate&amp;quot;
    phx-submit=&amp;quot;save&amp;quot;&amp;gt;

  &amp;lt;%= label f, :title %&amp;gt;
  &amp;lt;%= text_input f, :title %&amp;gt;
  &amp;lt;%= error_tag f, :title %&amp;gt;

  &amp;lt;%= label f, :description %&amp;gt;
  &amp;lt;%= textarea f, :description %&amp;gt;
  &amp;lt;%= error_tag f, :description %&amp;gt;

  &amp;lt;%= label f, :author %&amp;gt;
  &amp;lt;%= select f, :author_id, Enum.map(@authors, &amp;amp;{&amp;amp;1.full_name, &amp;amp;1.id}) %&amp;gt;
  &amp;lt;%= error_tag f, :author_id %&amp;gt;

  &amp;lt;div&amp;gt;
    &amp;lt;%= submit &amp;quot;Save&amp;quot;, phx_disable_with: &amp;quot;Saving...&amp;quot; %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/.form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Already, we can see that the &lt;code&gt;form/1&lt;/code&gt; function component offers a clean and easy-to-read syntax for describing forms. Let&amp;#39;s break down the function invocation here. Then, we&amp;#39;ll trace what&amp;#39;s happening under the hood.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;form/1&lt;/code&gt; function component, like all function components, is called with one argument of the assigns. Some of the attributes passed as part of the assigns probably look familiar from working with &lt;code&gt;Phoenix.HTML.form_for/4&lt;/code&gt;. We pass in the changeset, an ID, and some LiveView form bindings. In fact, we can optionally pass in any of the same options you would give to &lt;code&gt;Phoenix.HTML.form_for/4&lt;/code&gt;, and the &lt;code&gt;form/3&lt;/code&gt; function component will use those options in the same way.&lt;/p&gt;
&lt;p&gt;In addition to the form options we&amp;#39;re giving to assigns, we also use the &lt;code&gt;let&lt;/code&gt; assigns to tell the function component to give a value back to the caller. More on this in a bit.&lt;/p&gt;
&lt;p&gt;Lastly, you&amp;#39;ll notice that we&amp;#39;re actually calling the &lt;code&gt;form/1&lt;/code&gt; function component with an opening and closing &lt;code&gt;&amp;lt;.form&amp;gt;&lt;/code&gt; tag, and we&amp;#39;ve enclosed the content of our form within those tags. This eloquent, declarative syntax is made possible by the Phoenix Component&amp;#39;s &lt;code&gt;render_slot/2&lt;/code&gt; functionality. We&amp;#39;ll see that in action later on in this post.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve seen how to call on the &lt;code&gt;form/1&lt;/code&gt; function component, let&amp;#39;s dive into the function&amp;#39;s implementation.&lt;/p&gt;
&lt;h2&gt;The &lt;code&gt;form/1&lt;/code&gt; Component Under the Hood&lt;/h2&gt;
&lt;p&gt;You already know that a function component takes in an argument of some assigns and returns some markup wrapped in a HEEx template. So, you won&amp;#39;t be surprised to see that at its core, the &lt;code&gt;form/1&lt;/code&gt; function component sets up a &lt;code&gt;Phoenix.HTML.Form&lt;/code&gt; struct and renders it in a HEEx template that returns an HTML form.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll break down this process one step at a time, beginning with the creation of the form struct.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Creating the &lt;code&gt;Phoenix.Form&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The first thing that the &lt;code&gt;form/1&lt;/code&gt; function does under the hood is to construct a &lt;code&gt;Phoenix.HTML.Form&lt;/code&gt; struct. This is constructed using the data in the assigns that we passed into our function call. &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view/blob/30ee942b3a18a9e2e1f222a76a707bfba7bd94f7/lib/phoenix_live_view/helpers.ex#L1034-L1044&quot;&gt;Let&amp;#39;s take a look at the code&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# Extract options and then to the same call as form_for
action = assigns[:action] || &amp;quot;#&amp;quot;
form_for = assigns[:for] || raise ArgumentError, &amp;quot;missing :for assign to form&amp;quot;
form_options = assigns_to_attributes(assigns, [:action, :for])

# Since FormData may add options, read the actual options from form
%{options: opts} =
  form = %Phoenix.HTML.Form{
    Phoenix.HTML.FormData.to_form(form_for, form_options)
    | action: action
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, it casts the data from the assigns into the same format that &lt;code&gt;Phoenix.HTML.form_for/4&lt;/code&gt; uses to construct form structs. Then, it initializes a new struct.&lt;/p&gt;
&lt;p&gt;Next up, the function constructs the form method, CSRF token, and multi-part setting from the data in the form struct, &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view/blob/30ee942b3a18a9e2e1f222a76a707bfba7bd94f7/lib/phoenix_live_view/helpers.ex#L1046-L1059&quot;&gt;like this&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# And then process method, csrf_token, and multipart as in form_tag
{method, opts} = Keyword.pop(opts, :method, &amp;quot;post&amp;quot;)
{method, hidden_method} = form_method(method)

{csrf_token, opts} =
  Keyword.pop_lazy(opts, :csrf_token, fn -&amp;gt;
    if method == &amp;quot;post&amp;quot;, do: Plug.CSRFProtection.get_csrf_token_for(action)
  end)

opts =
  case Keyword.pop(opts, :multipart, false) do
    {false, opts} -&amp;gt; opts
    {true, opts} -&amp;gt; Keyword.put(opts, :enctype, &amp;quot;multipart/form-data&amp;quot;)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the form struct and options in place, we then move on to constructing the assigns that will be &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view/blob/30ee942b3a18a9e2e1f222a76a707bfba7bd94f7/lib/phoenix_live_view/helpers.ex#L1062-L1068&quot;&gt;rendered in the HEEx template here&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;assigns =
  LiveView.assign(assigns,
    form: form,
    csrf_token: csrf_token,
    hidden_method: hidden_method,
    attrs: [action: action, method: method] ++ opts
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For LiveView to track changes to assigns values rendered by a function component, it &lt;em&gt;must&lt;/em&gt; render a valid &lt;code&gt;assigns&lt;/code&gt; either passed in as the only argument given to the function or created via a call to &lt;code&gt;Phoenix.LiveView.assign/3&lt;/code&gt; or &lt;code&gt;Phoenix.LiveView.assign_new/3&lt;/code&gt;. So, the function component uses &lt;code&gt;LiveView.assign/3&lt;/code&gt; here to construct a new set of assigns to render in the HEEx template.&lt;/p&gt;
&lt;p&gt;With the assigns in place, the function will then render the template. Let&amp;#39;s take a look at that now.&lt;/p&gt;
&lt;h3&gt;Rendering the HEEx Template&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;form/1&lt;/code&gt; function component, like all function components, returns some markup wrapped in a HEEx template. Let&amp;#39;s take a look at &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view/blob/30ee942b3a18a9e2e1f222a76a707bfba7bd94f7/lib/phoenix_live_view/helpers.ex#L1070-L1080&quot;&gt;that return value&lt;/a&gt; now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt; ~H&amp;quot;&amp;quot;&amp;quot;
&amp;lt;form {@attrs}&amp;gt;
  &amp;lt;%= if @hidden_method &amp;amp;&amp;amp; @hidden_method not in ~w(get post) do %&amp;gt;
    &amp;lt;input name=&amp;quot;_method&amp;quot; type=&amp;quot;hidden&amp;quot; value={@hidden_method}&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;lt;%= if @csrf_token do %&amp;gt;
    &amp;lt;input name=&amp;quot;_csrf_token&amp;quot; type=&amp;quot;hidden&amp;quot; value={@csrf_token}&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;lt;%= render_slot(@inner_block, @form) %&amp;gt;
&amp;lt;/form&amp;gt;
&amp;quot;&amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unsurprisingly, the &lt;code&gt;form/1&lt;/code&gt; function component simply returns a HEEx template wrapping a call to an HTML &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;. Let&amp;#39;s dig into how the template uses some of the assigns established in the previous step.&lt;/p&gt;
&lt;p&gt;First up, you can see that the &lt;code&gt;@attrs&lt;/code&gt; assigns is interpolated directly into the opening &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tag. This will render the tag with the appropriate &lt;code&gt;method=&lt;/code&gt; and &lt;code&gt;action=&lt;/code&gt; attributes. Next up, you can see that the &lt;code&gt;@hidden_method&lt;/code&gt; assigns determines if and how to populate the hidden input. Then the &lt;code&gt;@csrf&lt;/code&gt; token, if present, is added to the HTML form in another hidden input.&lt;/p&gt;
&lt;p&gt;Most of this template has been pretty straightforward so far. The HEEx template renders, and HTML is constructed from various assigns values. Next up, we&amp;#39;ll look at how the form fields we specified between our opening and closing &lt;code&gt;&amp;lt;.form&amp;gt;&lt;/code&gt; tags are rendered into the template with the component slot functionality.&lt;/p&gt;
&lt;h3&gt;Render the Inner Block with Phoenix Component Slots&lt;/h3&gt;
&lt;p&gt;Phoenix Components implement a feature called &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#module-slots&quot;&gt;&amp;quot;slots&amp;quot;&lt;/a&gt;. Slots enable us to give blocks to our function component calls, nesting them within opening and closing function component tags like regular HTML tags. Slots are the reason for the &lt;code&gt;form/1&lt;/code&gt; syntax we used above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;.form ...assigns&amp;gt;
  &amp;lt;!-- form fields --&amp;gt;
&amp;lt;/.form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s how it works. Suppose you call on a function component with opening and closing function component tags. That function component&amp;#39;s template renders the content in those tags with the help of the &lt;code&gt;render_slot/2&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at an example. Recall the &lt;code&gt;UserDetails.contact_info/1&lt;/code&gt; function component we defined earlier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppLive.UserDetails do
  use Phoenix.Component

  def contact_info(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Phone:&amp;lt;/strong&amp;gt;&amp;lt;%= @user.phone_number %&amp;gt;&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Email:&amp;lt;/strong&amp;gt;&amp;lt;%= @user.email %&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can refactor it to use slots like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppLive.UserDetails do
  use Phoenix.Component

  def contact_info(assigns) do
    ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;div class=&amp;quot;contact-info&amp;quot;&amp;gt;
      &amp;lt;%= render_slot(@inner_block) %&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;quot;&amp;quot;&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we have a dynamic function component we can use to render any type of contact info:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;UserDetails.contact_info user=&amp;quot;{@current_user}&amp;quot;&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Phone:&amp;lt;/strong&amp;gt;&amp;lt;%= @current_user.phone_number %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/UserDetails.contact_info&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;UserDetails.contact_info user={@current_user}&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;strong&amp;gt;Address:&amp;lt;/strong&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;%= @current_user.street_address %&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;%= @current_user.city %&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;%= @current_user.zip_code %&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;&amp;lt;%= @current_user.country %&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
  &amp;lt;/p&amp;gt;
&amp;lt;/UserDetails.contact_info&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The HTML markup we include between the opening and closing function component tags becomes available in the function component as the &lt;code&gt;@inner_block&lt;/code&gt; assigns. The &lt;code&gt;render_slot/2&lt;/code&gt; function renders that content for us.&lt;/p&gt;
&lt;p&gt;We can clean this up even further with the &lt;code&gt;let&lt;/code&gt; assigns to yield a variable from the function component&amp;#39;s template back to the calling template. Let&amp;#39;s take a look.&lt;/p&gt;
&lt;p&gt;First, we&amp;#39;ll call the function component with an assigns of &lt;code&gt;let&lt;/code&gt; set equal to a variable, &lt;code&gt;user&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;UserDetails.contact_info let=&amp;quot;{user}&amp;quot; user=&amp;quot;{@current_user}&amp;quot;&amp;gt;
  &amp;lt;!-- coming soon --&amp;gt;
&amp;lt;/UserDetails.contact_info&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we&amp;#39;ll update the function component&amp;#39;s call to &lt;code&gt;render_slot/2&lt;/code&gt; by invoking it with a second argument of the &lt;code&gt;@user&lt;/code&gt; assignment, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def contact_info(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;div class=&amp;quot;contact-info&amp;quot;&amp;gt;
    &amp;lt;%= render_slot(@inner_block, @user) %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function component sets the variable we specified in the &lt;code&gt;let&lt;/code&gt; assignment equal to the value of whatever is passed in as the second argument to &lt;code&gt;render_slot/2&lt;/code&gt;. Now, the inner content between the function component&amp;#39;s opening and closing tags in the calling template has access to the &lt;code&gt;user&lt;/code&gt; variable. We can update our inner block to look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;UserDetails.contact_info let=&amp;quot;{user}&amp;quot; user=&amp;quot;{@current_user}&amp;quot;&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Phone:&amp;lt;/strong&amp;gt;&amp;lt;%= user.phone_number %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/UserDetails.contact_info&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this basic understanding of slots in place, let&amp;#39;s revisit the &lt;code&gt;form/1&lt;/code&gt; template:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;~H&amp;quot;&amp;quot;&amp;quot;
&amp;lt;form {@attrs}&amp;gt;
  &amp;lt;%= if @hidden_method &amp;amp;&amp;amp; @hidden_method not in ~w(get post) do %&amp;gt;
  &amp;lt;input name=&amp;quot;_method&amp;quot; type=&amp;quot;hidden&amp;quot; value=&amp;quot;{@hidden_method}&amp;quot; /&amp;gt;
  &amp;lt;% end %&amp;gt; &amp;lt;%= if @csrf_token do %&amp;gt;
  &amp;lt;input name=&amp;quot;_csrf_token&amp;quot; type=&amp;quot;hidden&amp;quot; value=&amp;quot;{@csrf_token}&amp;quot; /&amp;gt;
  &amp;lt;% end %&amp;gt; &amp;lt;%= render_slot(@inner_block, @form) %&amp;gt;
&amp;lt;/form&amp;gt;
&amp;quot;&amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, its calling &lt;code&gt;render_slot/2&lt;/code&gt; with the &lt;code&gt;@inner_block&lt;/code&gt; assignment and the &lt;code&gt;@form&lt;/code&gt; assignment. Recall that we invoked &lt;code&gt;form/1&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;.form
    let={f}
    for={@changeset}
    id=&amp;quot;book-form&amp;quot;
    phx-change=&amp;quot;validate&amp;quot;
    phx-submit=&amp;quot;save&amp;quot;&amp;gt;

  &amp;lt;%= label f, :title %&amp;gt;
  &amp;lt;%= text_input f, :title %&amp;gt;
  &amp;lt;%= error_tag f, :title %&amp;gt;

  &amp;lt;!-- ... --&amp;gt;
&amp;lt;/.form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, the form fields render as the &lt;code&gt;@inner_block&lt;/code&gt; assignment. The call to &lt;code&gt;&amp;lt;.form&amp;gt;&lt;/code&gt;
establishes a variable &lt;code&gt;f&lt;/code&gt;, which gets set to a value of the second argument passed to &lt;code&gt;render_slot/2&lt;/code&gt;. The second argument to &lt;code&gt;render_slot/2&lt;/code&gt; is the &lt;code&gt;@form&lt;/code&gt; assignment, pointing to our &lt;code&gt;Phoenix.HTML.Form&lt;/code&gt; struct. So, the inner content in our calling template can use the &lt;code&gt;f&lt;/code&gt; variable to reference the form struct and build out the Phoenix form to render.&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s it!&lt;/p&gt;
&lt;h2&gt;Wrap Up: Demystifying Phoenix LiveView&amp;#39;s Form Function Component&lt;/h2&gt;
&lt;p&gt;While the call to the &lt;code&gt;form/1&lt;/code&gt; function component can seem mysterious, tracing the code under the hood isn&amp;#39;t too daunting.&lt;/p&gt;
&lt;p&gt;To recap: we can see that the function establishes a Phoenix form and assembles some assigns. Then, it returns a HEEx template that renders an HTML form with the assigns. The HEEx template uses Phoenix Component&amp;#39;s slot functionality to render the inner content of our specified form fields, and yields the Phoenix form back to the calling template where we construct those fields.&lt;/p&gt;
&lt;p&gt;I hope that this dive under the hood of the &lt;code&gt;form/1&lt;/code&gt; function component has not only demystified that function, but also given you a deeper understanding of how you can use function components and slots in your own live views. Now, you&amp;#39;re ready to build out your own extensible function component that dynamically renders different inner blocks of content.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Guide to Secure Elixir Package Updates</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/03/15/a-guide-to-secure-elixir-package-updates.html"/>
    <id>https://blog.appsignal.com/2022/03/15/a-guide-to-secure-elixir-package-updates.html</id>
    <published>2022-03-15T00:00:00+00:00</published>
    <updated>2022-03-15T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Explore how you can use Hex dependencies for safer package updates in Elixir.</summary>
    <content type="html">&lt;p&gt;Keeping your dependencies up-to-date is essential to ensure that your
applications stay healthy, secure, and performant. Thankfully, the BEAM
ecosystem has its own package manager, &lt;a href=&quot;https://hex.pm/&quot;&gt;Hex&lt;/a&gt;, which is fast, mature,
and simple to use.&lt;/p&gt;
&lt;p&gt;This article explores the available tools and commands to manage
Hex dependencies and some tips to make the process more enjoyable.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;List Updatable Dependencies in Your Elixir App&lt;/h2&gt;
&lt;p&gt;You can use the
commands below to understand the relationships between dependencies before you attempt to update any of them.&lt;/p&gt;
&lt;p&gt;List all your application&amp;#39;s dependencies with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps --all
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;* bunt 0.2.0 (Hex package) (mix)
  locked at 0.2.0 (bunt) 7af5c7e0
  ok
* castore 0.1.15 (Hex package) (mix)
  locked at 0.1.15 (castore) c69379b9
  ok
* connection 1.1.0 (Hex package) (mix)
  locked at 1.1.0 (connection) 722c1eb0
  ok
* cowboy 2.9.0 (Hex package) (rebar3)
  locked at 2.9.0 (cowboy) 2c729f93
  ok
* cowboy_telemetry 0.4.0 (Hex package) (rebar3)
  locked at 0.4.0 (cowboy_telemetry) 7d98bac1
  ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or you can choose to print them in a tree format with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.tree
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produces output like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;short
├── credo ~&amp;gt; 1.6 (Hex package)
│   ├── bunt ~&amp;gt; 0.2.0 (Hex package)
│   ├── file_system ~&amp;gt; 0.2.8 (Hex package)
│   └── jason ~&amp;gt; 1.0 (Hex package)
├── ecto_psql_extras ~&amp;gt; 0.6 (Hex package)
│   ├── ecto_sql ~&amp;gt; 3.4 (Hex package)
│   ├── postgrex &amp;gt;= 0.15.7 (Hex package)
│   └── table_rex ~&amp;gt; 3.1.1 (Hex package)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To produce an image output, run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.tree --format dot &amp;amp;&amp;amp; dot -Tpng deps_tree.dot -o deps_tree.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This option requires &lt;code&gt;Graphviz&lt;/code&gt;. &lt;a href=&quot;https://graphviz.org/download/&quot;&gt;Read these Graphviz instructions&lt;/a&gt; to install it on your system.&lt;/p&gt;
&lt;p&gt;Then open the created &lt;code&gt;deps_tree.png&lt;/code&gt; file with a viewer of
your choice. Being able to quickly visualize dependencies can help you
decide whether a package is worth keeping in your mix.lock. A package could be
pulling too many sub-dependencies or might not even be used in your app. Remember,
the fewer dependencies, the easier it is to keep things up-to-date.&lt;/p&gt;
&lt;p&gt;When you remove a dependency from mix.exs, it will remain in mix.lock.
To remove unused dependencies, run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.clean --unlock --unused
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Check for Outdated Dependencies with Hex&lt;/h3&gt;
&lt;p&gt;After making sense of your dependencies tree and performing any necessary cleanups,
check for outdated packages with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix hex.outdated --all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output will resemble:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Dependency              Current  Latest  Status
bunt                    0.2.0    0.2.0   Up-to-date
cowlib                  2.11.0   2.11.0  Up-to-date
credo                   1.6.1    1.6.3   Update possible
db_connection           2.4.1    2.4.1   Up-to-date
decimal                 2.0.0    2.0.0   Up-to-date
earmark_parser          1.4.19   1.4.20  Update possible
postgrex                0.15.13  0.16.2  Update not possible

To view the diffs in each available update, visit:
https://hex.pm/l/AsY7q
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The &lt;code&gt;--all&lt;/code&gt; flag shows all outdated packages, including the children of packages defined in mix.exs.&lt;/p&gt;
&lt;p&gt;Notice the link in the output above. Hex prepares a nice page for us to inspect the diffs:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-03/hexdiff.png&quot; alt=&quot;hexdiff-screenshot&quot;/&gt;&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;&lt;strong&gt;Pro-Tip&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Use the &lt;code&gt;--within-requirements&lt;/code&gt; flag in your CI to notify you of
available updates.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix hex.outdated --within-requirements 1&amp;gt;/dev/null || echo &amp;#39;Updates available!&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output of Elixir&amp;#39;s package management tasks tends to be concise,
well-documented and precisely guides you towards actions.&lt;/p&gt;
&lt;h2&gt;Inspecting Changes with Hex&lt;/h2&gt;
&lt;p&gt;To see changes between two package versions in the terminal, run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;# This will display the diff for the package opus
mix hex.package diff opus 0.7.0 0.8.1
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt;diff --git a/var/folders/nc/t881hgn/T/opus-0.7.0-9F0FC44B/mix.exs b/var/folders/nc/t881/T/opus-0.8.1-2BEF6AED/mix.exs
index 0aba420..0c1ad3e 100644
--- a/var/folders/nc/t881/T/opus-0.7.0-9F0FC44B/mix.exs
+++ b/var/folders/nc/t881/T/opus-0.8.1-2BEF6AED/mix.exs
@@ -4,7 +4,7 @@ defmodule Opus.Mixfile do
   def project do
     [
       app: :opus,
-      version: &amp;quot;0.7.0&amp;quot;,
+      version: &amp;quot;0.8.1&amp;quot;,
       elixir: &amp;quot;~&amp;gt; 1.6&amp;quot;,
       elixirc_paths: elixirc_paths(Mix.env()),
       build_embedded: Mix.env() == :prod,
@@ -39,7 +39,7 @@ defmodule Opus.Mixfile do
   defp deps do
     [
       {:retry, &amp;quot;~&amp;gt; 0.8&amp;quot;},
-      {:telemetry, &amp;quot;~&amp;gt; 0.4&amp;quot;, optional: true},
+      {:telemetry, &amp;quot;~&amp;gt; 0.4 or ~&amp;gt; 1.0&amp;quot;, optional: true},
       {:credo, &amp;quot;~&amp;gt; 0.8.10&amp;quot;, only: [:dev, :test], runtime: false},
       {:ex_doc, &amp;quot;~&amp;gt; 0.24.2&amp;quot;, only: :dev, runtime: false},
       {:dialyxir, &amp;quot;~&amp;gt; 1.0.0-rc.3&amp;quot;, only: [:dev, :test], runtime: false},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can view the diff in the browser by navigating to:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://diff.hex.pm/diff/&amp;lt;package_name&amp;gt;/&amp;lt;version1&amp;gt;..&amp;lt;version2&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For example: &lt;a href=&quot;https://diff.hex.pm/diff/opus/0.7.0..0.8.1&quot;&gt;https://diff.hex.pm/diff/opus/0.7.0..0.8.1&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hex Diff generates a highlighted git diff which you can view in the
browser. You can share the link or even highlight a specific row.&lt;/p&gt;
&lt;p&gt;Third-party dependencies are essentially somebody&amp;#39;s code downloaded from
the internet, which ends up in your application. There is no shortage of
examples where packages have been hijacked and malicious versions
uploaded.&lt;/p&gt;
&lt;p&gt;Ideally, you should inspect the diff of every update.
Hex seems to be the only package manager with this built-in feature at
the moment.&lt;/p&gt;
&lt;h2&gt;Browsing Changelogs&lt;/h2&gt;
&lt;p&gt;Ultimately, an update might be available, but is it safe to apply it? Are
there any code or configuration changes required for the update to work without issues?
The diff between two package versions may contain thousands of lines of
templates, tests, and docs that might not seem relevant to you.&lt;/p&gt;
&lt;p&gt;Furthermore, a package might not even follow &lt;a href=&quot;https://semver.org/&quot;&gt;Semver&lt;/a&gt; (semver indicates whether
the update is safe in compatibility terms).&lt;/p&gt;
&lt;p&gt;Commonly, package maintainers keep a changelog to
communicate notable changes and upgrade paths concisely. &lt;a href=&quot;https://keepachangelog.com/en/1.0.0/&quot;&gt;Read
more about the benefits of keeping a changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now the bad news: not all packages have a changelog.
So let&amp;#39;s go changelog hunting!&lt;/p&gt;
&lt;p&gt;The following task will fetch information for the &lt;code&gt;credo&lt;/code&gt; package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix hex.info credo
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;A static code analysis tool with a focus on code consistency and teaching.

Config: {:credo, &amp;quot;~&amp;gt; 1.6&amp;quot;}
Locked version: 1.6.3
Releases: 1.6.3, 1.6.2, 1.6.1, 1.6.0, 1.6.0-rc.1, 1.6.0-rc.0, 1.5.6, 1.5.5, ...

Licenses: MIT
Links:
  Changelog: https://github.com/rrrene/credo/blob/master/CHANGELOG.md &amp;lt;--- Here
  GitHub: https://github.com/rrrene/credo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the maintainer has added a link to the changelog, so that&amp;#39;s
nice of them.&lt;/p&gt;
&lt;p&gt;There is even a link to the changelog in the HexDocs, which some developers may
find really handy:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-03/hexdocs.png&quot; alt=&quot;hexdocs&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tips:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure there&amp;#39;s a link to your changelog in &lt;code&gt;mix.exs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Include the changelog in the hexdocs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Automated Changelog Fetching&lt;/h3&gt;
&lt;p&gt;Hunting for changelogs can get tedious after a while, especially if you want to update many
packages.
Thankfully, there is now an &lt;em&gt;experimental&lt;/em&gt; package for that.&lt;/p&gt;
&lt;p&gt;You can add it in your dependencies with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:changelog, &amp;quot;~&amp;gt; 0.1&amp;quot;, only: [:dev, :test], runtime: false}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ensure it is fetched:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Invoke it for all updatable packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix changelog
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or for a number of packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix changelog tailwind jason

Package: tailwind
Current version: 0.1.4
Latest version:  0.1.5
Hexdiff: https://diff.hex.pm/diff/tailwind/0.1.4..0.1.5

## v0.1.5 (2022-01-18)
  * Prune app.js css import to remove required manual step on first install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This will only print the version to update to, a link to the diff, and the changelog when there is a more recent version.&lt;/p&gt;
&lt;p&gt;I wrote this &lt;a href=&quot;https://github.com/zorbash/changelog&quot;&gt;open-source task&lt;/a&gt;. It uses
some heuristics to locate the changelog by retrieving the Hex package metadata from the API,
falling back to common locations in the repo.&lt;/p&gt;
&lt;p&gt;My wish is that Hex will standardize including a link to a changelog in mix.exs and
&lt;code&gt;mix hex.info&lt;/code&gt;, and that Hex Diff will be enhanced to include changelog
information.&lt;/p&gt;
&lt;h2&gt;Updating Dependencies in Elixir&lt;/h2&gt;
&lt;p&gt;To update all dependencies, run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.update --all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the output, you will see version updates in the following format:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Upgraded:
  credo 1.6.1 =&amp;gt; 1.6.3
  earmark_parser 1.4.19 =&amp;gt; 1.4.20
  ecto_sql 3.7.1 =&amp;gt; 3.7.2
  ex_doc 0.27.3 =&amp;gt; 0.28.2 (minor)
  makeup 1.0.5 =&amp;gt; 1.1.0
  mint 1.4.0 =&amp;gt; 1.4.1
  nimble_parsec 1.2.0 =&amp;gt; 1.2.2
  nimble_pool 0.2.5 =&amp;gt; 0.2.6
  phoenix_live_dashboard 0.6.2 =&amp;gt; 0.6.5
  phoenix_live_view 0.17.5 =&amp;gt; 0.17.7
  phoenix_view 1.1.0 =&amp;gt; 1.1.2
  plug 1.12.1 =&amp;gt; 1.13.3
  postgrex 0.15.13 =&amp;gt; 0.16.2 (minor)
  tailwind 0.1.4 =&amp;gt; 0.1.5
New:
  hpax 0.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the same as running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix deps.unlock --all &amp;amp;&amp;amp; mix deps.get
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Keep in mind that this task will try to upgrade to versions that match the specifications in your mix.exs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def deps do
  [
    {:some_package, &amp;quot;~&amp;gt; 0.9&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even if there is a more recent 1.0 version for &lt;code&gt;some_package&lt;/code&gt;, it does
not match the specification above, and it won&amp;#39;t be upgraded.
You will have to change your mix.exs and try again.&lt;/p&gt;
&lt;p&gt;As we saw in the first section of this article, there is a task you can
run to check if an update is possible for a package.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix hex.outdated some_package
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;Dependency              Current  Latest  Status
some_package            0.9.0    1.0.0   Update not possible
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There might be a conflict in some cases where the package resolution
cannot find a version to satisfy the dependencies in mix.exs.&lt;/p&gt;
&lt;p&gt;A workaround (that you should use with caution) is &lt;code&gt;override&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def deps do
  [
    {:some_package, &amp;quot;~&amp;gt; 1.0&amp;quot;},
    {:other_package, &amp;quot;~&amp;gt; 2.0&amp;quot;, override: true}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, the dependency will override any other definitions by other dependencies.&lt;/p&gt;
&lt;h2&gt;Further Reading: Keep Your Package Updates Safe in Elixir&lt;/h2&gt;
&lt;p&gt;Elixir comes with a whole arsenal of tools to manage dependencies. Try
to master them and stir your mix.exs often. Read changelogs and
diffs to ensure your updates are safe.&lt;/p&gt;
&lt;p&gt;Here are some resources that can help you dive deeper into this topic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/mix/Mix.Tasks.Deps.html&quot;&gt;HexDocs:mix deps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hex.pm/docs/usage&quot;&gt;HexDocs:usage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/hex/Mix.Tasks.Hex.Outdated.html&quot;&gt;HexDocs:mix hex.outdated&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hex.pm/about&quot;&gt;Hex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://graphviz.org/download/&quot;&gt;Graphviz-install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://keepachangelog.com/en/1.0.0/&quot;&gt;Keepachangelog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://semver.org/&quot;&gt;Semver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zorbash/changelog&quot;&gt;Changelog-repo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Functional Programming in Elixir with Witchcraft</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/02/08/functional-programming-in-elixir-with-witchcraft.html"/>
    <id>https://blog.appsignal.com/2022/02/08/functional-programming-in-elixir-with-witchcraft.html</id>
    <published>2022-02-08T00:00:00+00:00</published>
    <updated>2022-02-08T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how you can use the Witchcraft library to do Haskell-style programming in Elixir.</summary>
    <content type="html">&lt;p&gt;While Elixir is a functional programming language, it is different from most of the other popular functional languages like Haskell, Scala, OCaml, and F#.&lt;/p&gt;
&lt;p&gt;Elixir pragmatically handles concurrent systems with high fault tolerance. In other words, Elixir is an FP language because this naturally fits it, and not for its own sake. So, porting idioms blindly from Haskell to Elixir can lead to undesired results.&lt;/p&gt;
&lt;p&gt;At the same time, Elixir users should more frequently visit the whole wonderful universe of functors, monads, and other curiosities. Good libraries have been introduced for operating with algebraic structures.&lt;/p&gt;
&lt;p&gt;In this article, I want to introduce you to a library called Witchcraft and show how you can use it to emulate Haskell-style programming in Elixir.&lt;/p&gt;
&lt;h2&gt;What is Witchcraft?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://witchcrafters.github.io/&quot;&gt;Witchcraft&lt;/a&gt; is a library written by &lt;a href=&quot;https://twitter.com/expede?lang=en&quot;&gt;Brooklyn Zelenka&lt;/a&gt; that provides Elixir programmers with predefined abstractions for writing Haskell-like code. Witchcraft takes into account the eccentricities of Elixir, such as the frequent use of the pipe operator.&lt;/p&gt;
&lt;p&gt;In other words, Witchcraft is a library for writing Haskell &amp;#39;fan fiction&amp;#39; in Elixir.&lt;/p&gt;
&lt;p&gt;It connects with a few other libraries. All in all, the whole Witchcraft complex consists of four parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/witchcrafters/quark&quot;&gt;Quark&lt;/a&gt;&lt;/strong&gt; provides some functional building blocks, including flipping arguments of a function in place, a macro for currying functions, and other commonly used things.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/witchcrafters/type_class&quot;&gt;TypeClass&lt;/a&gt;&lt;/strong&gt; provides a good interface for generating type classes and their instances.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/witchcrafters/witchcraft&quot;&gt;Witchcraft&lt;/a&gt;&lt;/strong&gt; implements common algebraic and categorical abstractions, such as monads, functors, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/witchcrafters/algae&quot;&gt;Algae&lt;/a&gt;&lt;/strong&gt; implements a domain-specific language (DSL) for creating composite data types like you would in Haskell, and also contains commonly-used composite data types.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, let’s try working with the library.&lt;/p&gt;
&lt;h2&gt;String Validation and Processing with Witchcraft&lt;/h2&gt;
&lt;p&gt;We will go through a credit card validation exercise.&lt;/p&gt;
&lt;p&gt;Given a string that should contain a credit card number, we need to make sure that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it contains 16 digits&lt;/li&gt;
&lt;li&gt;it has at least two different digits&lt;/li&gt;
&lt;li&gt;the final digit is even&lt;/li&gt;
&lt;li&gt;the sum of the digits is more than 16&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will do this exercise with &lt;code&gt;Either&lt;/code&gt;, one of the predefined data types that the Witchcraft complex offers.&lt;/p&gt;
&lt;h3&gt;Set Up Witchcraft&lt;/h3&gt;
&lt;p&gt;First, add the necessary libraries to your &lt;code&gt;mix.exs&lt;/code&gt; file and run &lt;code&gt;mix deps.get&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  defp deps do
    [
      {:witchcraft, &amp;quot;~&amp;gt; 1.0&amp;quot;},
      {:algae, &amp;quot;~&amp;gt; 1.2&amp;quot;},
    ]
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Parsing the String&lt;/h3&gt;
&lt;p&gt;First, make a new module and import Witchcraft at the top of the module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Card do
  use Witchcraft

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, write a function to parse the string into a list of digits and remove all non-digit items.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def get_digits(cardnumber) do
  cardnumber
  |&amp;gt; String.split(&amp;quot;&amp;quot;, trim: true)
  |&amp;gt; Enum.map(fn x -&amp;gt; Integer.parse(x) end)
  |&amp;gt; Enum.filter(fn x -&amp;gt; x != :error end)
  |&amp;gt; Enum.map(fn {int, _rest} -&amp;gt; int end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code above, we split the card number into characters and map &lt;code&gt;Integer.parse&lt;/code&gt; (safe integer conversion) over them. &lt;code&gt;Integer.parse&lt;/code&gt; returns either &lt;code&gt;{int, rest_of_binary}&lt;/code&gt; or &lt;code&gt;:error&lt;/code&gt;. We filter out the errors and unpack the tuples with the last two functions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;iex(1)&amp;gt; Card.get_digits(&amp;quot;3456-3233-5689-4445&amp;quot;)
[3, 4, 5, 6, 3, 2, 3, 3, 5, 6, 8, 9, 4, 4, 4, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, we can write our first validation function with &lt;code&gt;Either&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Quick Intro to the &lt;code&gt;Either&lt;/code&gt; Data Type&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Either&lt;/code&gt; is a type that contains one of two different options: &lt;code&gt;Left&lt;/code&gt; or &lt;code&gt;Right&lt;/code&gt;. Each of these wraps another type. &lt;code&gt;Left&lt;/code&gt; stores failures, and &lt;code&gt;Right&lt;/code&gt; stores successes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-haskell&quot;&gt;-- Either data type as defined in Haskell
data Either a b = Left a | Right b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Usually, we return it from computations that can fail when you want to know what kind of error made them fail.&lt;/p&gt;
&lt;p&gt;When working with Witchcraft, you can use the predefined &lt;a href=&quot;https://github.com/witchcrafters/algae/blob/main/lib/algae/either.ex&quot;&gt;Algae.Either&lt;/a&gt; to create new instances of the &lt;code&gt;Either&lt;/code&gt; data type. We can do that by using one of two structs: &lt;code&gt;%Algae.Either.Left{left: value}&lt;/code&gt; or &lt;code&gt;%Algae.Either.Right{right: value}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most likely, you&amp;#39;ve already run into it somewhere. In other languages, it’s sometimes called &lt;code&gt;Result&lt;/code&gt; (in Rust, for example). It’s also structurally identical to the result tuple frequently used in Elixir.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:ok, result} -&amp;gt; {:right, result} -&amp;gt; %Algae.Either.Right{right: result}
{:error, reason} -&amp;gt; {:left, reason} -&amp;gt; %Algae.Either.Left{left: reason}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In fact, we could technically use the result tuple for our exercise. I&amp;#39;ve constructed it this way on purpose, so you can explore the machinery of Witchcraft while staying on more or less stable ground.&lt;/p&gt;
&lt;h3&gt;Example of &lt;code&gt;Either&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Let’s look at an example of &lt;code&gt;Either&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We have parsed a list of digits from the given string, and now we want to know whether there are 16 items in the list. If we took the easy way out, we could write something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def sixteen_digits(cardnumber), do: Enum.count(cardnumber) == 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, the function above is not very composable: the return value loses the card number, so we won’t be able to pipe the result to do further computations on it.&lt;/p&gt;
&lt;p&gt;Therefore, we want the result to be a more complicated structure such as &lt;code&gt;Either&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If there are 16 digits in the list, we want to return an &lt;code&gt;Either.Right&lt;/code&gt; with the list.&lt;/li&gt;
&lt;li&gt;If there is a different number of digits, we want to return an &lt;code&gt;Either.Left&lt;/code&gt; with &lt;code&gt;:not_16_digits&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And here’s the function to do that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def sixteen_digits(cardnumber) do
  case Enum.count(cardnumber) do
    16 -&amp;gt; %Algae.Either.Right{right: cardnumber}
    _ -&amp;gt; %Algae.Either.Left{left: :not_16_digits}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Let’s try it out in &lt;code&gt;iex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;iex(1)&amp;gt; right_number = Card.get_digits(&amp;quot;3456-3233---5689-4445&amp;quot;)
[3, 4, 5, 6, 3, 2, 3, 3, 5, 6, 8, 9, 4, 4, 4, 5]
iex(2)&amp;gt; Card.sixteen_digits(right_number)
%Algae.Either.Right{right: [3, 4, 5, 6, 3, 2, 3, 3, 5, 6, 8, 9, 4, 4, 4, 5]}
iex(3)&amp;gt; wrong_number = Card.get_digits(&amp;quot;444&amp;quot;)
[4, 4, 4]
iex(4)&amp;gt; Card.sixteen_digits(wrong_number)
%Algae.Either.Left{left: :not_16_digits}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Other Validation Functions&lt;/h3&gt;
&lt;p&gt;In the same way, we can make a validation rule for each requirement.&lt;/p&gt;
&lt;p&gt;I suggest you try doing it yourself first since they will be similar to the first example.&lt;/p&gt;
&lt;p&gt;To remind you, here are the conditions we need to check:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The number has at least two different digits.&lt;/li&gt;
&lt;li&gt;The final digit of the number is even.&lt;/li&gt;
&lt;li&gt;The sum of the digits is more than 16.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of the conditions should have its own function. Each of the functions should take a list of numbers and return:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%Algae.Either.Right{}&lt;/code&gt; with the list inside if the condition is fulfilled&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%Algae.Either.Left{}&lt;/code&gt; with the reason inside if the condition is not fulfilled&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are ready to proceed, here are the functions that I will use further on in this article:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def two_unique_digits(cardnumber) do
  unique =
    cardnumber
    |&amp;gt; Enum.uniq()
    |&amp;gt; Enum.count()

  case unique &amp;gt;= 2 do
    true -&amp;gt; %Algae.Either.Right{right: cardnumber}
    _ -&amp;gt; %Algae.Either.Left{left: :not_2_unique_digits}
  end
end

def final_even(cardnumber) do
  last_digit = Enum.at(cardnumber, -1)

  case rem(last_digit, 2) do
    0 -&amp;gt; %Algae.Either.Right{right: cardnumber}
    _ -&amp;gt; %Algae.Either.Left{left: :last_not_even}
  end
end

def sum_greater_than_16(cardnumber) do
  case Enum.sum(cardnumber) &amp;gt;= 16 do
    true -&amp;gt; %Algae.Either.Right{right: cardnumber}
    _ -&amp;gt; %Algae.Either.Left{left: :sum_smallr_than_16}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Connecting the Functions&lt;/h3&gt;
&lt;p&gt;But how can we join these functions together? Each of them takes a list but returns a struct. We can’t pipe them into each other because their types don’t match up.&lt;/p&gt;
&lt;p&gt;To chain them, we need something that knows how to unwrap &lt;code&gt;Algae.Either&lt;/code&gt; and apply other functions to what&amp;#39;s inside, and Witchcraft has just the thing we need.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;definst Witchcraft.Chain, for: Algae.Either.Left do
  def chain(left, _), do: left
end

definst Witchcraft.Chain, for: Algae.Either.Right do
  def chain(%Right{right: data}, link), do: link.(data)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;From &lt;a href=&quot;https://github.com/witchcrafters/algae/blob/main/lib/algae/either.ex&quot;&gt;Algae.Either&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/witchcraft/Witchcraft.Chain.html#chain/1&quot;&gt;&lt;code&gt;chain&lt;/code&gt;&lt;/a&gt;, which can also be written in Witchcraft as &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; (or &lt;code&gt;bind&lt;/code&gt;), is the famous bind operator from Haskell: &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;. Let’s understand what it does.&lt;/p&gt;
&lt;p&gt;As defined for &lt;code&gt;Either&lt;/code&gt;, it will take a value — either &lt;code&gt;Left &lt;/code&gt; or &lt;code&gt;Right&lt;/code&gt; — and a function from a regular value to &lt;code&gt;Either&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the case of &lt;code&gt;Left&lt;/code&gt;, it will ignore the function and pass the value further. In the case of &lt;code&gt;Right&lt;/code&gt;, it will apply the function to the value inside &lt;code&gt;Right&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In our code, we can conveniently use &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; so that it looks pipe-y.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def parse_number(cardnumber) do
  cardnumber
  |&amp;gt; get_digits()
  |&amp;gt; sixteen_digits()
    &amp;gt;&amp;gt;&amp;gt; fn x -&amp;gt; two_unique_digits(x) end
    &amp;gt;&amp;gt;&amp;gt; fn x -&amp;gt; final_even(x) end
    &amp;gt;&amp;gt;&amp;gt; fn x -&amp;gt; sum_greater_than_16(x) end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, the capture syntax (&lt;code&gt;&amp;amp;two_unique_digits/1&lt;/code&gt;) doesn’t work here. (The macro will expand the code to nested captures, which Elixir doesn’t allow you to do via &lt;code&gt;&amp;amp;&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;Combining the &lt;code&gt;Either&lt;/code&gt; data type and its defined chain function lets us build up a chain of functions. Even though they take a list and return an &lt;code&gt;Either&lt;/code&gt;, the functions can be chained to arrive at a result. The whole chain will return the list in case of success and the first encountered error in the case of failure.&lt;/p&gt;
&lt;p&gt;We can try it out in &lt;code&gt;iex&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;iex(1)&amp;gt; Card.parse_number(&amp;quot;4444-444-222-1&amp;quot;)
%Algae.Either.Left{left: :not_16_digits}
iex(2)&amp;gt; Card.parse_number(&amp;quot;4444-4444-4444-4444&amp;quot;)
%Algae.Either.Left{left: :not_2_unique_digits}
iex(3)&amp;gt; Card.parse_number(&amp;quot;4444-4444-4444-4435&amp;quot;)
%Algae.Either.Left{left: :last_not_even}
iex(4)&amp;gt; Card.parse_number(&amp;quot;1020-0000-0000-0000&amp;quot;)
%Algae.Either.Left{left: :sum_smaller_than_16}
iex(5)&amp;gt; Card.parse_number(&amp;quot;4545-3232-5423-6788&amp;quot;)
%Algae.Either.Right{right: [4, 5, 4, 5, 3, 2, 3, 2, 5, 4, 2, 3, 6, 7, 8, 8]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From this point onward, you can claim to have written monadic code in Elixir.&lt;/p&gt;
&lt;h3&gt;Tinkering With the Codebase&lt;/h3&gt;
&lt;p&gt;Here are some minor changes we can make to the code so it looks nicer. These are not essential to your understanding but can give you more practice with the code example in question.&lt;/p&gt;
&lt;p&gt;First off, Witchcraft provides a very handy &lt;code&gt;~&amp;gt;&lt;/code&gt; operator that does the same as piping into &lt;code&gt;Enum.map&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can use it in our &lt;code&gt;get_digits&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def get_digits(cardnumber) do
  cardnumber
  |&amp;gt; String.split(&amp;quot;&amp;quot;, trim: true)
  ~&amp;gt; fn x -&amp;gt; Integer.parse(x) end
  |&amp;gt; Enum.filter(fn x -&amp;gt; x != :error end)
  ~&amp;gt; fn {int, _rest} -&amp;gt; int end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, empty lists will cause some run-time errors with the &lt;code&gt;Enum.at&lt;/code&gt; that we used, and having empty inputs probably isn’t part of the plan, so we can reject empty strings right at the start.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def get_digits(cardnumber) do
  digits =
    cardnumber
    |&amp;gt; String.split(&amp;quot;&amp;quot;, trim: true)
    ~&amp;gt; fn x -&amp;gt; Integer.parse(x) end
    |&amp;gt; Enum.filter(fn x -&amp;gt; x != :error end)
    ~&amp;gt; fn {int, _rest} -&amp;gt; int end

  case digits do
    [] -&amp;gt; %Algae.Either.Left{left: :empty_input}
    _ -&amp;gt; %Algae.Either.Right{right: digits}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, there is a macro that you can use in &lt;code&gt;parse_number&lt;/code&gt; to simulate a more Haskell-like way of writing a sequence of actions in a certain context. This style is frequently called the &lt;a href=&quot;https://hexdocs.pm/witchcraft/Witchcraft.Monad.html#monad/2&quot;&gt;do-notation&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def parse_number(cardnumber) do

  monad %Algae.Either.Right{} do
    digits &amp;lt;- get_digits(cardnumber)
    a &amp;lt;- sixteen_digits(digits)
    b &amp;lt;- two_unique_digits(a)
    c &amp;lt;- final_even(b)
    d &amp;lt;- sum_greater_than_16(c)
    return(d)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the code sample above, we provide the kind of container that we will operate with — &lt;code&gt;%Algae.Either.Right{}&lt;/code&gt;. Then we can do actions inside it, and the &lt;a href=&quot;https://hexdocs.pm/witchcraft/Witchcraft.Monad.html#monad/2&quot;&gt;&lt;code&gt;monad&lt;/code&gt;&lt;/a&gt; macro will automatically chain our functions. In the end, it will return whatever we put in the return statement (but wrapped in the container).&lt;/p&gt;
&lt;p&gt;It&amp;#39;s very powerful, but also very confusing at first. If it is hard to understand what’s happening here, I encourage you to try out &lt;code&gt;monad []&lt;/code&gt; first since it is very similar to &lt;a href=&quot;https://elixir-lang.org/getting-started/comprehensions.html&quot;&gt;list comprehensions&lt;/a&gt;. In fact, if you think of this macro as generalized list comprehensions, you won&amp;#39;t err too much.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;Either&lt;/code&gt; and the Result Tuple in Elixir&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Either&lt;/code&gt; is very similar to the result tuple in Elixir, and I’ve done that on purpose to keep you on somewhat familiar ground.&lt;/p&gt;
&lt;p&gt;In fact, you can implement the same thing without using Witchcraft.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Card2 do

  def get_digits(cardnumber) do
    digits =
      cardnumber
      |&amp;gt; String.split(&amp;quot;&amp;quot;, trim: true)
      |&amp;gt; Enum.map(fn x -&amp;gt; Integer.parse(x) end)
      |&amp;gt; Enum.filter(fn x -&amp;gt; x != :error end)
      |&amp;gt; Enum.map(fn {int, _rest} -&amp;gt; int end)
  end

  def sixteen_digits(cardnumber) do
    case Enum.count(cardnumber) do
      16 -&amp;gt; {:ok, cardnumber}
      _ -&amp;gt; {:error, :not_16_digits}
    end
  end

  def two_unique_digits(cardnumber) do
    unique =
      cardnumber
      |&amp;gt; Enum.uniq()
      |&amp;gt; Enum.count()

    case unique &amp;gt;= 2 do
      true -&amp;gt; {:ok, cardnumber}
      _ -&amp;gt; {:error, :not_2_unique_digits}
    end
  end

  def final_even(cardnumber) do
    last_digit = Enum.at(cardnumber, -1)

    case rem(last_digit, 2) do
      0 -&amp;gt; {:ok, cardnumber}
      _ -&amp;gt; {:error, :last_not_even}
    end
  end

  def sum_greater_than_16(cardnumber) do
    case Enum.sum(cardnumber) &amp;gt;= 16 do
      true -&amp;gt; {:ok, cardnumber}
      _ -&amp;gt; {:error, :sum_smaller_than_16}
    end
  end

  def parse_number(cardnumber) do
    digits = get_digits(cardnumber)

    sixteen_digits(digits)
    |&amp;gt; chain(&amp;amp;two_unique_digits/1)
    |&amp;gt; chain(&amp;amp;final_even/1)
    |&amp;gt; chain(&amp;amp;sum_greater_than_16/1)
  end

  defp chain({:ok, result}, f), do: f.(result)
  defp chain({:error, _error} = result, _f), do: result
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we could also have used a &lt;a href=&quot;https://www.openmymind.net/Elixirs-With-Statement/&quot;&gt;&lt;code&gt;with&lt;/code&gt; statement&lt;/a&gt;, which handles tagged result tuples in a monadic way.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def parse_number_with(cardnumber) do
    with digits &amp;lt;- get_digits(cardnumber),
         {:ok, a} &amp;lt;- sixteen_digits(digits),
         {:ok, b} &amp;lt;- two_unique_digits(a),
         {:ok, c} &amp;lt;- final_even(b),
         {:ok, d} &amp;lt;- sum_greater_than_16(c)
  do
    {:ok, d}
  else
      err -&amp;gt; err
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But the benefit of Witchcraft is that you get a specific data type with a specific chain function and a large set of types, type classes, and functions, all of which work well with each other to support a particular programming style.&lt;/p&gt;
&lt;h2&gt;Why Use Witchcraft to Write Haskell-style Elixir?&lt;/h2&gt;
&lt;p&gt;There are quite a few benefits to using Witchcraft when writing Elixir:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Powerful abstractions&lt;/strong&gt; - for example, we have seen the &lt;code&gt;monad&lt;/code&gt; macro, which generalizes over the &lt;code&gt;for&lt;/code&gt; and &lt;code&gt;with&lt;/code&gt; statements in Elixir. While &lt;code&gt;for&lt;/code&gt; and &lt;code&gt;with&lt;/code&gt; statements are monadic, they are basically made to handle just a few types (lists or tuples) in a certain way. This does cover a large part of your everyday needs, but there are other wonderful things you could create by applying the same pattern differently &lt;em&gt;once you see it&lt;/em&gt;. For example, &lt;a href=&quot;https://wiki.haskell.org/All_About_Monads#A_Catalog_of_Standard_Monads&quot;&gt;Haskell&amp;#39;s wiki lists nine standard monads&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-set patterns of code shared between typed functional programming languages.&lt;/strong&gt; If you know these patterns, you can basically go to any typed FP language, check the syntax for them, and continue working with essentially no productivity loss. It&amp;#39;s the opposite of macros: it works the same way everywhere :)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More elegant code&lt;/strong&gt; - for example, a monadic way of handling tuples lets us escape from writing many ugly nested case statements. While Elixir&amp;#39;s &lt;code&gt;with&lt;/code&gt; statement already solves this particular problem, there are plenty of other places to apply these tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, Elixir isn’t really built for writing code like this. Therefore, using Witchcraft can also result in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A certain amount of unnecessary ceremony&lt;/li&gt;
&lt;li&gt;Performance penalties&lt;/li&gt;
&lt;li&gt;Angry stares from people that read your code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, the most significant benefit of trying out this programming style in Elixir is to train your programmer brain. Even though your code might not use Witchcraft or exactly follow these patterns as you write Elixir, it is good to know what exists out there.&lt;/p&gt;
&lt;h2&gt;Summing Up and Further Witchcraft Resources&lt;/h2&gt;
&lt;p&gt;In this post, we looked at how you can write Haskell &amp;#39;fan fiction&amp;#39; in Elixir using Witchcraft with a credit card validation code example.&lt;/p&gt;
&lt;p&gt;Hopefully, you&amp;#39;ve seen that Witchcraft contains a ton of stuff, enough to satisfy your curiosity about this kind of programming and more.&lt;/p&gt;
&lt;p&gt;But, while it is a good tool for teaching FP concepts, there aren&amp;#39;t a lot of tutorials available. Brooklyn Zelenka did a &lt;a href=&quot;https://www.youtube.com/watch?v=psdG5iV57q0&quot;&gt;talk about Witchcraft&lt;/a&gt;, but there isn&amp;#39;t much else out there. If you would like to learn more about this programming style &lt;em&gt;right now&lt;/em&gt;, your best bet is to start exploring a language like Haskell, F#, or OCaml (the latter two also have pipes).&lt;/p&gt;
&lt;p&gt;Alternatively, you can explore typed BEAM by trying languages like &lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam&lt;/a&gt; or &lt;a href=&quot;https://www.hamler-lang.org/&quot;&gt;Hamler&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Securing Your Phoenix LiveView Apps</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/01/25/securing-your-phoenix-liveview-apps.html"/>
    <id>https://blog.appsignal.com/2022/01/25/securing-your-phoenix-liveview-apps.html</id>
    <published>2022-01-25T00:00:00+00:00</published>
    <updated>2022-01-25T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Explore how to group live routes in a secure live session and use function plugs to secure your live view routes.</summary>
    <content type="html">&lt;p&gt;LiveView is a compelling choice for building modern web apps. Built on top of Elixir&amp;#39;s OTP tooling, and leveraging WebSockets, it offers super fast real-time, interactive features alongside impressive developer productivity.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll show you how to secure your live view routes with function plugs and group live routes in a secure live session.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive straight in!&lt;/p&gt;
&lt;h2&gt;Using Live View to Build a Phoenix Web App&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll be building some authentication and authorization features into a Phoenix web app built with live view.&lt;/p&gt;
&lt;p&gt;The Arcade web app presents regular users with many online games to play. Our app has a survey feature that collects users&amp;#39; demographic data and game ratings. It also has an admin dashboard that should &lt;em&gt;only&lt;/em&gt; be accessible to app admins to view survey results.&lt;/p&gt;
&lt;p&gt;For the purpose of this post, we&amp;#39;ll assume that logged-in users can visit the &lt;code&gt;/games&lt;/code&gt; index and &lt;code&gt;/games/:id&lt;/code&gt; show routes to select and play a game, along with the &lt;code&gt;/survey&lt;/code&gt; route to fill out the user survey.&lt;/p&gt;
&lt;p&gt;Additionally, admin users should &lt;strong&gt;only&lt;/strong&gt; be able to visit the &lt;code&gt;/admin-dashboard&lt;/code&gt; page. We&amp;#39;ll assume that these pages and the live views that back them have already been built. Our focus is on introducing the authentication and authorization code we need to secure these live views.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started.&lt;/p&gt;
&lt;h2&gt;Protect Sensitive Routes in Your Phoenix LiveView App&lt;/h2&gt;
&lt;p&gt;This post assumes you&amp;#39;ve already built your registration and login flows, along with some function plugs for authenticating the current user and storing their token in the Phoenix session. I recommend using the &lt;a href=&quot;https://hexdocs.pm/phx_gen_auth/overview.html&quot;&gt;Phoenix Auth generator&lt;/a&gt; to generate this code for free.&lt;/p&gt;
&lt;p&gt;This generated code ensures that Phoenix will add a key of &lt;code&gt;:current_user&lt;/code&gt; to the &lt;code&gt;conn&lt;/code&gt; struct and a &lt;code&gt;&amp;quot;user_token&amp;quot;&lt;/code&gt; key to the session when a user logs in.&lt;/p&gt;
&lt;p&gt;Now, let&amp;#39;s start in the router by putting some live routes behind authentication.&lt;/p&gt;
&lt;p&gt;If you run the Phoenix Auth generator, you generate a module, &lt;code&gt;ArcadeWeb.UserAuth&lt;/code&gt;, that implements a function plug &lt;code&gt;require_authenticated_user/2&lt;/code&gt;, shown here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def require_authenticated_user(conn, _opts) do
  if conn.assigns[:current_user] do
    conn
  else
    conn
    |&amp;gt; put_flash(:error, &amp;quot;You must log in to access this page.&amp;quot;)
    |&amp;gt; maybe_store_return_to()
    |&amp;gt; redirect(to: Routes.user_session_path(conn, :new))
    |&amp;gt; halt()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The details of this function aren&amp;#39;t too important. Just understand that it takes in a first argument of the &lt;code&gt;conn&lt;/code&gt; struct and checks for the presence of a &lt;code&gt;:current_user&lt;/code&gt; key. If one is found, it returns the conn. If not, then it redirects to the login path.&lt;/p&gt;
&lt;p&gt;When the auth generator creates the &lt;code&gt;UserAuth&lt;/code&gt; module, it also imports into your router, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# router.ex
import ArcadeWeb.UserAuth
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can create a new router scope using this function plug. Let&amp;#39;s require that a user is logged in for access to the scope routes, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_authenticated_user]
  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the product index, show routes, and the &lt;code&gt;/survey&lt;/code&gt; route that any authenticated user can currently visit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_authenticated_user]
  live &amp;quot;/products&amp;quot;, ProductLive.Index
  live &amp;quot;/products/:id&amp;quot;, ProductLive.Show
  live &amp;quot;/survey&amp;quot;, SurveyLive
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when a user visits &lt;code&gt;/products&lt;/code&gt; or any other route in our new scope, Phoenix invokes the &lt;code&gt;require_authenticated_user&lt;/code&gt; function plug. Believe it or not, that&amp;#39;s all we have to do to restrict our live routes to logged-in users.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;We can take a similar approach to authorizing admins to visit the &lt;code&gt;/admin-dashboard&lt;/code&gt;. We&amp;#39;ll add a new function plug to the &lt;code&gt;UserAuth&lt;/code&gt; module, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def require_admin_user(%{current_user: current_user} = conn, _opts) do
  if current_user.admin do
    conn
  else
    conn
    |&amp;gt; put_flash(:error, &amp;quot;You must log in to access this page.&amp;quot;)
    |&amp;gt; maybe_store_return_to()
    |&amp;gt; redirect(to: Routes.page_path(conn))
    |&amp;gt; halt()
  end
end

def require_admin_user(conn, _opts) do
  conn
    |&amp;gt; put_flash(:error, &amp;quot;You must log in to access this page.&amp;quot;)
    |&amp;gt; maybe_store_return_to()
    |&amp;gt; redirect(to: Routes.page_path(conn))
    |&amp;gt; halt()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the function plug is invoked with a &lt;code&gt;conn&lt;/code&gt; struct that does not contain the current user, we will redirect to the root path.&lt;/p&gt;
&lt;p&gt;If the function plug is called with a &lt;code&gt;conn&lt;/code&gt; that contains a current user, we will check if that user is an admin. If so, return the &lt;code&gt;conn&lt;/code&gt;, otherwise, redirect. The details of our check for the admin status, &lt;code&gt;current_user.admin&lt;/code&gt;, don&amp;#39;t really matter here. Your app may implement admin logic differently. The main takeaway is that we now have a function plug that can &lt;em&gt;authorize&lt;/em&gt; certain routes by enforcing that the current user is present &lt;em&gt;and&lt;/em&gt; an admin.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s now use our new function plug in our router. We&amp;#39;ll create a second scope with a pipeline that uses the &lt;code&gt;require_admin_user/1&lt;/code&gt; function plug:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_admin_user]
  live &amp;quot;/admin-dashboard&amp;quot;, Admin.DashboardLive
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great! If a user points their browser at &lt;code&gt;/admin-dashboard&lt;/code&gt;, our function plug will be invoked.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ve ensured that our live view routes are secure with nothing more than normal Phoenix auth plugs. We can implement authentication — requiring the presence of a current user — and authorization — requiring that the current user has specific permissions or roles — just like you would for regular Phoenix routes.&lt;/p&gt;
&lt;p&gt;Now, let&amp;#39;s look at a new LiveView feature for grouping live routes together and a security challenge that it presents.&lt;/p&gt;
&lt;h2&gt;Group Live Views in a Live Session&lt;/h2&gt;
&lt;p&gt;You&amp;#39;ll use live sessions to group similar live routes with shared layouts and auth logic. Grouping live routes together in a live session means that we can live redirect to those routes from any other route in the same live session group.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Helpers.html#live_redirect/2&quot;&gt;live redirect&lt;/a&gt; is a special kind of redirect that leverages the existing WebSocket connection, minimizing network traffic and keeping your live view speedy.&lt;/p&gt;
&lt;p&gt;When you live redirect from one live view to another in the same live session, the current live view process terminates. The new live view is mounted over the current WebSocket connection without reloading the whole page.&lt;/p&gt;
&lt;p&gt;This works great for live views that share a layout. The shared layout that frames the live view content will stay in place, and only the portion of the page that renders the current live view within that layout will change.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s create our first live session group now for the routes behind regular user authentication:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_authenticated_user]

  live_session :user, root_layout: {ArcadeWeb.LayoutView, &amp;quot;authenticated.html&amp;quot;} do
    live &amp;quot;/products&amp;quot;, ProductLive.Index
    live &amp;quot;/products/:id&amp;quot;, ProductLive.Show
    live &amp;quot;/survey&amp;quot;, SurveyLive
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we establish a live session block to contain all of our routes that need to be authenticated for regular users and tell them to share a common layout found in &lt;code&gt;lib/arcade_web/templates/layout/authenticated.html.heex&lt;/code&gt;. You might notice that the &lt;code&gt;live_session&lt;/code&gt; macro is called with a first argument, &lt;code&gt;:user&lt;/code&gt;. We&amp;#39;ll see how that comes into play in just a bit.&lt;/p&gt;
&lt;p&gt;Whenever a user live redirects from the &lt;code&gt;/products&lt;/code&gt; route to &lt;code&gt;/products/:id&lt;/code&gt;, for example, the existing WebSocket connection will not terminate. Instead, we&amp;#39;ll kill the current live view process, mount the new live view, and only re-render the necessary portions of the page within the shared layout.&lt;/p&gt;
&lt;h3&gt;Grouping Live Routes: The Security Problem&lt;/h3&gt;
&lt;p&gt;This approach presents a security challenge. If we re-use the existing WebSocket connection, we &lt;em&gt;won&amp;#39;t&lt;/em&gt; be sending a new HTTP request, and we &lt;em&gt;won&amp;#39;t&lt;/em&gt; go through the plug pipeline defined in our router.&lt;/p&gt;
&lt;p&gt;So we must perform authentication and authorization in our router to prevent direct navigation to sensitive routes from the browser. We must also ensure that our live views can perform their own authentication and authorization &lt;em&gt;every time they mount&lt;/em&gt; (whether due to a user pointing their browser directly at a live route or a live redirect between live routes in a shared live session).&lt;/p&gt;
&lt;p&gt;Luckily for us, LiveView presents an API for performing authorization and authentication when the live view mounts, making it easy for us to apply this logic across all live routes in a shared session. Let&amp;#39;s take a look.&lt;/p&gt;
&lt;h2&gt;Protect Live Views When They Mount&lt;/h2&gt;
&lt;p&gt;The LiveView framework allows us to hook into a callback function that will run whenever a live view mounts. The &lt;code&gt;on_mount/4&lt;/code&gt; lifecycle hook will fire before the live view mounts, making it the perfect place to isolate re-usable auth logic that can be shared among live views in a live session.&lt;/p&gt;
&lt;p&gt;Start by defining a module that implements an &lt;code&gt;on_mount/4&lt;/code&gt; function, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.UserAuthLive do
  import Phoenix.LiveView
  alias Arcade.Accounts

  def on_mount(:user, params, %{&amp;quot;user_token&amp;quot; =&amp;gt; user_token} = _session, socket) do
    socket =
      socket
      |&amp;gt; assign(:current_user, Accounts.get_user_by_session_token(user_token))
    if socket.assigns.current_user do
      {:cont, socket}
    else
      {:halt, redirect(socket, to: &amp;quot;/login&amp;quot;)}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function will be called with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a first argument of the atom that we passed to our &lt;code&gt;live_session&lt;/code&gt; macro&lt;/li&gt;
&lt;li&gt;a second argument of any params that were part of the incoming web request&lt;/li&gt;
&lt;li&gt;a third argument of the session containing the &lt;code&gt;&amp;quot;user_token&amp;quot;&lt;/code&gt; used to identify the current user&lt;/li&gt;
&lt;li&gt;a fourth argument of the socket (remember, if you use the Phoenix Auth generator, Phoenix will add this &lt;code&gt;&amp;quot;user_token&amp;quot;&lt;/code&gt; to the session when a user logs in.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We perform some basic authentication here by looking up the current user and assigning the result to the socket. If the socket then contains a current user value rather than &lt;code&gt;nil&lt;/code&gt;, we continue. Otherwise, we halt and redirect. Any &lt;code&gt;on_mount/4&lt;/code&gt; function must conform to this API, returning the &lt;code&gt;:cont&lt;/code&gt; tuple or the &lt;code&gt;:halt&lt;/code&gt; tuple.&lt;/p&gt;
&lt;p&gt;Next up, let&amp;#39;s tell our live session to apply this &lt;code&gt;on_mount/4&lt;/code&gt; callback to all of the live routes in its grouping:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_authenticated_user]

  live_session :user, on_mount: {UserAuthLive, :user}, root_layout: {ArcadeWeb.LayoutView, &amp;quot;authenticated.html&amp;quot;} do
    live &amp;quot;/products&amp;quot;, ProductLive.Index
    live &amp;quot;/products/:id&amp;quot;, ProductLive.Show
    live &amp;quot;/survey&amp;quot;, SurveyLive
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whenever there is a live redirect to &lt;code&gt;&amp;quot;/products&amp;quot;&lt;/code&gt; route (or any other route in that live session), the given live view will invoke &lt;code&gt;ArcadeWeb.UserAuthLive.on_mount/4&lt;/code&gt; with a first argument of &lt;code&gt;:user&lt;/code&gt; and our authentication logic will execute. Furthermore, any live view within the live session will mount with the &lt;code&gt;:current_user&lt;/code&gt; already set in its socket assigns, since we&amp;#39;re adding it in the &lt;code&gt;on_mount&lt;/code&gt; callback.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s set up a similar callback for the admin live session. Add this function to &lt;code&gt;UserAuthLive&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def on_mount(:admin, params, %{&amp;quot;user_token&amp;quot; =&amp;gt; user_token} = _session, socket) do
  socket =
    socket
    |&amp;gt; assign(:current_user, Accounts.get_user_by_session_token(user_token))
  if socket.assigns.current_user.admin do
    {:cont, socket}
  else
    {:halt, redirect(socket, to: &amp;quot;/&amp;quot;)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, when &lt;code&gt;on_mount/4&lt;/code&gt; is called with a first argument of &lt;code&gt;:admin&lt;/code&gt;, we will authorize the current user &lt;em&gt;and&lt;/em&gt; authenticate them as an admin. Let&amp;#39;s add this to a new live session for the admin-protected routes now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt; scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_admin_user]
  live_session :admin, on_mount: {UserAuthLive, :admin}, root_layout: {ArcadeWeb.LayoutView, &amp;quot;admin.html&amp;quot;} do
    live &amp;quot;/admin-dashboard&amp;quot;, Admin.DashboardLive
    # more admin routes
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we group admin-protected routes with a shared admin layout. And whenever any of the live views in this session block mount, the &lt;code&gt;UserAuthLive.on_mount/4&lt;/code&gt; function will be called with the &lt;code&gt;:admin&lt;/code&gt; atom as a first argument. This ensures that only admin users can access those pages, even when live redirected.&lt;/p&gt;
&lt;p&gt;Thanks to Elixir&amp;#39;s pattern matching, we can group all of our auth-related &lt;code&gt;on_mount/4&lt;/code&gt; callbacks in a shared module and implement however many &lt;code&gt;live_session&lt;/code&gt; blocks we need to organize our live views.&lt;/p&gt;
&lt;h2&gt;Wrap Up: Easily Group Live Views to Secure Your Phoenix LiveView App&lt;/h2&gt;
&lt;p&gt;In this post, we explored how LiveView allows you to group live routes in a shared session. Grouping enables live views to easily share a layout and implement shared authentication and authorization logic.&lt;/p&gt;
&lt;p&gt;Remember, you must authenticate and authorize &lt;em&gt;both&lt;/em&gt; your protected routes in the router &lt;em&gt;and&lt;/em&gt; your live views when they mount. Reach for function plug pipelines to achieve the former, and live session and the &lt;code&gt;on_mount/4&lt;/code&gt; callback to accomplish the latter. With this combination of tools, you can bulletproof your live views, making them highly secure and capable of sophisticated authorization logic.&lt;/p&gt;
&lt;p&gt;I hope you&amp;#39;ve found this post useful. Until next time: happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Build Interactive Phoenix LiveView UIs with Components</title>
    <link rel="alternate" href="https://blog.appsignal.com/2022/01/11/build-interactive-phoenix-liveview-uis-with-components.html"/>
    <id>https://blog.appsignal.com/2022/01/11/build-interactive-phoenix-liveview-uis-with-components.html</id>
    <published>2022-01-11T00:00:00+00:00</published>
    <updated>2022-01-11T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn how to make use of functional components to create complex Phoenix LiveView UIs.</summary>
    <content type="html">&lt;p&gt;LiveView empowers developers to build interactive, single-page web apps with ease by providing a framework that eliminates the need for guesswork.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll take a look at how you can layer simple, single-purpose functional components to wrap up shared presentation logic. We&amp;#39;ll also use more sophisticated live components to craft easy-to-maintain single-page flows that handle complex user interactions.&lt;/p&gt;
&lt;p&gt;Along the way, you&amp;#39;ll gain a solid understanding of working with HEEx — Phoenix and LiveView&amp;#39;s new templating engine — and you&amp;#39;ll see some of LiveView&amp;#39;s out-of-the-box function components in action.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive in!&lt;/p&gt;
&lt;h2&gt;The Feature: Compose a User Survey UI for a Phoenix LiveView App&lt;/h2&gt;
&lt;p&gt;Before we dive into writing any actual code, let&amp;#39;s talk about the feature we&amp;#39;ll build. Imagine that you&amp;#39;re responsible for a Phoenix web app, Arcade, that provides in-browser games to users. A user can log in, select a game to play, and even invite friends to play games with them.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll build out a &amp;quot;user survey&amp;quot; feature that asks the user to fill out some demographic info about themselves and then provide a rating for each of several games. We&amp;#39;ll focus on that second part of the survey — the game rating forms.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s lay out what we&amp;#39;ll build in a bit more detail. We&amp;#39;ll begin with a parent live view that lives at the &lt;code&gt;/survey&lt;/code&gt; route, &lt;code&gt;ArcadeWeb.SurveyLive&lt;/code&gt;. This live view will render a child functional component, &amp;quot;ratings index&amp;quot;. The ratings index component will iterate over the games and show a game rating if one by the current user exists, or a form for a new rating if not. If users haven&amp;#39;t completed a game rating, they will see a list of forms to rate each game 1-5 stars. If they have completed some (or all) ratings, they will see those displayed and forms to submit ratings for the games they have not yet rated.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a look at how it will work:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-01/rating-form-partially-complete.png&quot; alt=&quot;ratings form partially complete&quot;/&gt;&lt;/p&gt;
&lt;p&gt;With our plan in place, we&amp;#39;re ready to start writing code.&lt;/p&gt;
&lt;h2&gt;Define the Parent Live View&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll build a route first, then mount and render the initial live view.&lt;/p&gt;
&lt;h3&gt;Define the Survey Route&lt;/h3&gt;
&lt;p&gt;Our first job is to establish a route. The survey will live at &lt;code&gt;/survey&lt;/code&gt;, and it should only work for authenticated users so we can deliver a survey to single, identifiable users. We&amp;#39;ll tie the route to the yet-to-be-written &lt;code&gt;SurveyLive&lt;/code&gt; live view, with the &lt;code&gt;:index&lt;/code&gt; live action, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# router.ex
scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_authenticated_user]
    live &amp;quot;/survey&amp;quot;, SurveyLive, :index
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code assumes you&amp;#39;ve used the &lt;a href=&quot;https://github.com/aaronrenner/phx_gen_auth&quot;&gt;Phoenix Auth generator&lt;/a&gt; to add authentication to your Phoenix app. The details of authentication aren&amp;#39;t important for our purposes here. Just know that the &lt;code&gt;survey&lt;/code&gt; route is a protected route that requires an authenticated user. This means that when a logged-in user points their browser at &lt;code&gt;/survey&lt;/code&gt;, the &lt;code&gt;SurveyLive&lt;/code&gt; view will mount with a &lt;code&gt;session&lt;/code&gt; argument that contains a key of &lt;code&gt;&amp;quot;user_token&amp;quot;&lt;/code&gt; pointing to a token we can use to identify the current user. The generator also gives us a function, &lt;code&gt;Accounts.get_user_by_session_token(user_token)&lt;/code&gt;, that we will use to fetch the user for that token.&lt;/p&gt;
&lt;p&gt;With our route established, it&amp;#39;s time to define the &lt;code&gt;SurveyLive&lt;/code&gt; live view.&lt;/p&gt;
&lt;h3&gt;Mount the Survey Live View&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;mount/3&lt;/code&gt; function builds the initial state for &lt;code&gt;SurveyLive&lt;/code&gt;. Let&amp;#39;s think a bit about that initial state. We need to use the current user to build our survey&amp;#39;s demographic and rating portions since a demographic belongs to a user and a rating belongs to a game and a user. So we want to store that user in the live view&amp;#39;s state. This way, we can make it available to the rating form component later. Now, let&amp;#39;s implement a &lt;code&gt;mount/3&lt;/code&gt; function that adds the current user to socket assigns, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/arcade_web/live/survey_live.ex
defmodule ArcadeWeb.SurveyLive do
  use ArcadeWeb, :live_view

  def mount(_params, %{&amp;quot;user_token&amp;quot; =&amp;gt; user_token}, socket) do
    {:ok,
      socket
      |&amp;gt; assign(
          :current_user,
          Accounts.get_user_by_session_token(user_token))}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, we&amp;#39;re ready to render a simple version of our survey live view.&lt;/p&gt;
&lt;h3&gt;Render the Survey Live View&lt;/h3&gt;
&lt;p&gt;We won&amp;#39;t provide a &lt;code&gt;render/1&lt;/code&gt; function, instead we&amp;#39;ll use a template — &lt;code&gt;lib/arcade_web/live/survey_live.html.heex&lt;/code&gt;. Let&amp;#39;s keep it simple for now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;section class=&amp;quot;row&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Survey&amp;lt;/h2&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reload your browser, and you&amp;#39;ll see the bare-bones template shown here:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-01/survey-template-simple-content.png&quot; alt=&quot;simple survey template&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We have the basic framework for our survey UI in place. Now, we&amp;#39;re ready to build our first function component.&lt;/p&gt;
&lt;h2&gt;List Ratings in Phoenix LiveView&lt;/h2&gt;
&lt;p&gt;Before we build our ratings index function component, let&amp;#39;s talk about what function components are and how they work. A function component takes in an &lt;code&gt;assigns&lt;/code&gt; argument and returns a HEEx template. Function components are implemented in modules that use the &lt;code&gt;Phoenix.Component&lt;/code&gt; behaviour, which also gives us a convenient syntax for rendering function components.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re almost ready to define our function component. Let&amp;#39;s take a step back and discuss HEEx.&lt;/p&gt;
&lt;h3&gt;Understanding HEEx Templates&lt;/h3&gt;
&lt;p&gt;A HEEx template is any file ending in the &lt;code&gt;.heex&lt;/code&gt; extension that is implicitly rendered by a live view, or any markup rendered by a live view or component that is encapsulated in the &lt;code&gt;~H&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt; tags. The HEEx templating engine is an extension of EEx. Just like EEx templates, HEEx will process template replacements within your HTML code. Everything between the &lt;code&gt;&amp;lt;%=&lt;/code&gt; and &lt;code&gt;%&amp;gt;&lt;/code&gt; expressions is a template replacement. HEEx will evaluate the Elixir code within those tags and replace them with the result.&lt;/p&gt;
&lt;p&gt;HEEx does more than just templating, though. It also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;provides compile-time HTML validations&lt;/li&gt;
&lt;li&gt;gives us a convenient component rendering syntax&lt;/li&gt;
&lt;li&gt;optimizes the amount of content sent over the wire, allowing LiveView to render &lt;em&gt;only those portions of the template that need updating when state changes&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HEEx is the default templating engine for Phoenix and LiveView. Any generated template files in your Phoenix app will be HEEx templates and end in the &lt;code&gt;.html.heex&lt;/code&gt; extension. When using inline &lt;code&gt;render/1&lt;/code&gt; functions in your live views, or function components, you&amp;#39;ll return HEEx templates with the &lt;code&gt;~H&lt;/code&gt; sigil.&lt;/p&gt;
&lt;p&gt;With that basic understanding in place, we&amp;#39;re ready to implement the ratings index function component.&lt;/p&gt;
&lt;h3&gt;Define the Function Component&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll build a rating index component responsible for orchestrating the state of &lt;em&gt;all&lt;/em&gt; the game ratings in our survey. This component will iterate over the games and render the rating details if a user rating exists, or the rating form if it doesn&amp;#39;t. The responsibility for rendering rating details will be handled by a &amp;quot;rating show&amp;quot; function component. A live &amp;quot;rating form&amp;quot; component will handle rendering and managing a rating form. More on live components in a bit.&lt;/p&gt;
&lt;p&gt;Meanwhile, &lt;code&gt;SurveyLive&lt;/code&gt; will continue to be responsible for managing the overall state and appearance of the survey page. The rating index component will receive the list of game ratings to render from the parent live view. The parent live view is responsible for maintaining and updating that list.&lt;/p&gt;
&lt;p&gt;In this way, we keep our code organized and easy to maintain because it adheres to the single responsibility principle — each component has one job to do. By layering these components within the parent &lt;code&gt;SurveyLive&lt;/code&gt; view, we compose a series of small, manageable pieces into one interactive feature — the user survey page.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll begin by implementing the &lt;code&gt;RatingLive.Index&lt;/code&gt; function component. Then, we&amp;#39;ll move on to the rating show component, followed by the rating form component.&lt;/p&gt;
&lt;p&gt;Create a file, &lt;code&gt;lib/arcade_web/live/rating_live/index.ex&lt;/code&gt;, and key in the following component definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.RatingLive.Index do
  use Phoenix.Component
  use Phoenix.HTML
  alias ArcadeWeb.RatingLive
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our function component uses the &lt;code&gt;Phoenix.Component&lt;/code&gt; behaviour which we need to render HEEx templates. Any module that implements &lt;em&gt;only&lt;/em&gt; function components will use this behaviour. You&amp;#39;ll use a different behaviour when building live or stateful components, which we&amp;#39;ll do later on in this post.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re also using the &lt;code&gt;Phoenix.HTML&lt;/code&gt; behaviour here to bring in the &lt;code&gt;Phoenix.HTML.raw/1&lt;/code&gt; function that we&amp;#39;ll use to render unicode characters — more on that in a bit. Finally, we&amp;#39;re aliasing the name of the component module itself so it&amp;#39;s easy to ergonomically invoke other function components defined within the module from within our main function component here.&lt;/p&gt;
&lt;p&gt;The entry point of our module will be the &lt;code&gt;games/1&lt;/code&gt; function. We&amp;#39;ll call on this function component from the parent live view to render the list of games. The function will take in an &lt;code&gt;assigns&lt;/code&gt; argument containing the list of games passed in from the parent &lt;code&gt;SurveyLive&lt;/code&gt; view. It will return a HEEx template that iterates over that list and renders &lt;em&gt;another&lt;/em&gt; function component to show the game rating details if a rating exists and the rating form live component if not. Define that function now, as shown here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def games(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;div class=&amp;quot;survey-component-container&amp;quot;&amp;gt;
    &amp;lt;.heading games={@games} /&amp;gt;
    &amp;lt;.list games={@games} current_user={@current_user}/&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;re composing our &lt;code&gt;games/1&lt;/code&gt; function out of two additional function components — &lt;code&gt;heading/1&lt;/code&gt; and &lt;code&gt;list/1&lt;/code&gt;. We call on those function components with the &lt;code&gt;.function_name assigns... /&amp;gt;&lt;/code&gt; syntax. This invokes the function component and passes in whatever assigns we provide as the &lt;code&gt;assigns&lt;/code&gt; argument to that function.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also worth noting the &lt;code&gt;{}&lt;/code&gt; interpolation syntax here, instead of the &lt;code&gt;&amp;lt;%= %&amp;gt;&lt;/code&gt; EEx tags you might be used to. This is because HEEx, unlike EEx, isn&amp;#39;t just responsible for evaluating and templating Elixir expressions into your HTML. It also parses and validates the HTML itself. So you can&amp;#39;t use the traditional EEx tags &lt;em&gt;inside&lt;/em&gt; HTML tags in a HEEx template. Instead, use curly braces to interpolate values inside HTML tags and function component calls, and use EEx tags when interpolating values in the body, or inner content, of those tags.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s build those additional function components now, starting with &lt;code&gt;heading/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def heading(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
    &amp;lt;h2&amp;gt;
      Ratings
      &amp;lt;%= if ratings_complete?(@games), do: raw &amp;quot;&amp;amp;#x2713;&amp;quot; %&amp;gt;
    &amp;lt;/h2&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;heading/1&lt;/code&gt; function is pretty small and single-purpose. It renders an &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; element that encapsulates some text along with a helper function that checks to see if &lt;em&gt;all&lt;/em&gt; of the games have a rating by the current user. If so, we render the unicode to a checkmark and the user can see that all of the ratings forms have been completed.&lt;/p&gt;
&lt;p&gt;Before we implement this helper function, let&amp;#39;s see how we&amp;#39;re going to render the index component with a list of games.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;When we render this index component from the &lt;code&gt;SurveyLive&lt;/code&gt; template, we&amp;#39;ll use the &lt;code&gt;SurveyLive&lt;/code&gt; view to query for the list of games with ratings by the current preloaded user.&lt;/p&gt;
&lt;p&gt;Then, we&amp;#39;ll pass that list of games down into the index component. So we can assume that each game in the &lt;code&gt;@games&lt;/code&gt; list has its &lt;code&gt;ratings&lt;/code&gt; list populated &lt;em&gt;only&lt;/em&gt; with a rating from the current user. With that in mind, we can implement the &lt;code&gt;ratings_complete?/1&lt;/code&gt; function to iterate over the list of games and return &lt;code&gt;true&lt;/code&gt; if there is a rating for every game. Add in your function now, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt; defp ratings_complete?(games) do
  Enum.all?(games, fn game -&amp;gt;
    length(game.ratings) == 1
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if a user has completed all of the game ratings, they&amp;#39;ll see the &amp;quot;Ratings&amp;quot; header with a nice checkmark next to it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-01/ratings-complete-header.png&quot; alt=&quot;ratings complete header&quot;/&gt;&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;heading/1&lt;/code&gt; function component out of the way, let&amp;#39;s turn our attention to &lt;code&gt;list/1&lt;/code&gt;. Add in this function now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def list(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;%= for {game, index} &amp;lt;- Enum.with_index(@games) do %&amp;gt;
    &amp;lt;%= if rating = List.first(game.ratings) do %&amp;gt;
      &amp;lt;h3&amp;gt;Show rating coming soon!&amp;lt;/h3&amp;gt;
    &amp;lt;% else %&amp;gt;
      &amp;lt;h3&amp;gt;Rating form coming soon!&amp;lt;/h3&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use a &lt;code&gt;for&lt;/code&gt; comprehension that maps over all of the games in the system, where each game&amp;#39;s &lt;code&gt;ratings&lt;/code&gt; list contains the single preloaded rating by the given user if one exists. Inside that comprehension, the template will render the rating details if a rating exists or a form for that rating if not. Nesting components in this manner lets the reader of the code deal with a tiny bit of complexity at a time.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll dig into this logic a bit more when we&amp;#39;re ready to implement these final two components. With the index component out of the way, we are ready to weave it into our &lt;code&gt;SurveyLive&lt;/code&gt; template.&lt;/p&gt;
&lt;h3&gt;Render the Component&lt;/h3&gt;
&lt;p&gt;The next bit of code we&amp;#39;ll write shows how the presentation of our view can change based on the contents of the socket. The &lt;code&gt;SurveyLive&lt;/code&gt; view will use the state of the overall survey to control what is shown to the user. This view holds the list of games, and their ratings by the current user, in state. It will pass this list into the &lt;code&gt;RatingLive.games/1&lt;/code&gt; function component as part of the component assigns. The contents of this list will allow the &lt;code&gt;games/1&lt;/code&gt; function component to determine if it should show rating details or a rating form.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s update &lt;code&gt;SurveyLive&lt;/code&gt; now to query for the list of games and their ratings from the current user and add them to socket assigns, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.SurveyLive do
  use ArcadeWeb, :live_view
  alias Arcade.Survey

  def mount(_params, %{&amp;quot;user_token&amp;quot; =&amp;gt; token}, socket) do
    {:ok,
     socket
     |&amp;gt; assign(:current_user, Accounts.get_user_by_session_token(token))
     |&amp;gt; assign(:games, Catalog.list_games_with_user_rating(user))}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assume that the &lt;code&gt;Catalog.list_games_with_user_rating/1&lt;/code&gt; context function returns the list of all games, with &lt;em&gt;only the rating by the given user&lt;/em&gt; preloaded, if any.&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;re ready to render our rating index function component from the &lt;code&gt;SurveyLive&lt;/code&gt; template:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;!-- lib/arcade_web/live/survey_live.html.heex --&amp;gt;
  &amp;lt;RatingLive.Index.games games={@games}
      current_user={@current_user} /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&amp;#39;re once again using the &lt;code&gt;&amp;lt;.function_component assigns... /&amp;gt;&lt;/code&gt; syntax to render our function component and the &lt;code&gt;{}&lt;/code&gt; interpolation syntax for interpolating within tags in a HEEx template.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;re rendering our &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt; function component with the game list, let&amp;#39;s build the stateless function component to show the existing rating for a game.&lt;/p&gt;
&lt;h2&gt;Show a Rating&lt;/h2&gt;
&lt;p&gt;We&amp;#39;re getting closer to the goal of showing ratings, step by step. Remember, we&amp;#39;ll show the existing ratings, and forms for ratings, otherwise.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s cover the case for ratings that exist first. We&amp;#39;ll define a stateless component to show a rating. Then, we&amp;#39;ll render that component from within the HEEx template returned by &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt;. Let&amp;#39;s get started.&lt;/p&gt;
&lt;h3&gt;Build the Function Component&lt;/h3&gt;
&lt;p&gt;Create a file, &lt;code&gt;lib/arcade_web/live/rating_live/show_component.ex&lt;/code&gt;, and key this in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.RatingLive.Show do
  use Phoenix.Component
  use Phoenix.HTML
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;re defining a module that uses the &lt;code&gt;Phoenix.Component&lt;/code&gt; behaviour and the &lt;code&gt;Phoenix.HTML&lt;/code&gt; behaviour, since we&amp;#39;ll once again need support for the &lt;code&gt;Phoenix.HTML.raw/1&lt;/code&gt; function to render unicode characters.&lt;/p&gt;
&lt;p&gt;Okay, let&amp;#39;s move on to the entry point of our function component, the &lt;code&gt;stars/1&lt;/code&gt; function. We&amp;#39;ll call this function from within the HEEx template returned by &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt; with an assigns that includes the given game&amp;#39;s rating by the current user.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;stars/1&lt;/code&gt; function will operate on this rating and use some helper functions to construct a list of filled and unfilled unicode star characters. We&amp;#39;ll construct that list using a simple pipeline, and then render it in a HEEx template, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def stars(assigns) do
  stars =
    filled_stars(assigns.rating.stars)
    |&amp;gt; Enum.concat(unfilled_stars(assigns.rating.stars))
    |&amp;gt; Enum.join(&amp;quot; &amp;quot;)

  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;div&amp;gt;
    &amp;lt;h4&amp;gt;
      &amp;lt;%= @game.name %&amp;gt;:&amp;lt;br/&amp;gt;
      &amp;lt;%= raw stars %&amp;gt;
    &amp;lt;/h4&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;filled_stars/1&lt;/code&gt; and &lt;code&gt;unfilled_stars/1&lt;/code&gt; helper functions are interesting. Take a look at them here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def filled_stars(stars) do
  List.duplicate(&amp;quot;&amp;amp;#x2605;&amp;quot;, stars)
end

def unfilled_stars(stars) do
  List.duplicate(&amp;quot;&amp;amp;#x2606;&amp;quot;, 5 - stars)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Examining our pipeline in the &lt;code&gt;stars/1&lt;/code&gt; function, we can see that we call on &lt;code&gt;filled_stars/1&lt;/code&gt; to produce a list of filled-in, or &amp;quot;checked&amp;quot;, star unicode characters corresponding to the number of stars the game rating has. Then, we pipe that into a call to &lt;code&gt;Enum.concat/2&lt;/code&gt; with a second argument of the output from &lt;code&gt;unfilled_stars/1&lt;/code&gt;. This second helper function produces a list of empty, or not checked, star characters for the remaining number of stars.&lt;/p&gt;
&lt;p&gt;For example, if the number of stars in the rating is 3, our pipeline of helper functions will create a list of three checked stars and two un-checked stars. Our pipeline concatenates the two lists together and joins them into a string of HTML that we can render in the template.&lt;/p&gt;
&lt;p&gt;We have everything we need to display a completed rating, so it&amp;#39;s time to roll several components up together.&lt;/p&gt;
&lt;h3&gt;Render the Component&lt;/h3&gt;
&lt;p&gt;We&amp;#39;re ready to implement the next phase of our plan. The &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt; function component iterates over the list of games in the &lt;code&gt;@games&lt;/code&gt; assigns. If a rating is present, we show it. Add in the call to our new &lt;code&gt;Show.stars/1&lt;/code&gt; component now, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def list(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;%= for {game, index} &amp;lt;- Enum.with_index(@games) do %&amp;gt;
    &amp;lt;%= if rating = List.first(game.ratings) do %&amp;gt;
      &amp;lt;Show.stars rating={rating} game={game} /&amp;gt;
    &amp;lt;% else %&amp;gt;
      &amp;lt;h3&amp;gt;Rating form coming soon!&amp;lt;/h3&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&amp;#39;s a straight &lt;code&gt;for&lt;/code&gt; comprehension with an &lt;code&gt;if&lt;/code&gt; statement. If a rating exists, we render the function component by calling on it with the &lt;code&gt;game&lt;/code&gt; and &lt;code&gt;rating&lt;/code&gt; assigns. If not, we need to render the form. Let&amp;#39;s build that form and render it now.&lt;/p&gt;
&lt;h2&gt;Submit a Rating&lt;/h2&gt;
&lt;p&gt;Our rating form will display the form and manage its state, validating and saving the rating. We&amp;#39;ll need to pass a game and user for our database relationships, and the game&amp;#39;s index in the parent LiveView&amp;#39;s &lt;code&gt;socket.assigns.games&lt;/code&gt; list. We&amp;#39;ll use this index later on to update &lt;code&gt;SurveyLive&lt;/code&gt; state efficiently.&lt;/p&gt;
&lt;h3&gt;Build the Rating Form Component&lt;/h3&gt;
&lt;p&gt;The component will be stateful since it needs to manage the state of the rating form and respond to user interactions to validate form changes and handle the form submission.&lt;/p&gt;
&lt;p&gt;A stateful, or live, component is any module that uses the &lt;code&gt;:live_component&lt;/code&gt; behaviour and renders a HEEx template. Such modules can implement the live component lifecycle functions, including &lt;code&gt;mount/3&lt;/code&gt;, &lt;code&gt;update/2&lt;/code&gt;, and &lt;code&gt;render/1&lt;/code&gt;, and respond to user events by implementing a &lt;code&gt;handle_event/3&lt;/code&gt; function. Let&amp;#39;s define our live component module now. Create a file, &lt;code&gt;lib/arcade_web/live/rating_live/form.ex&lt;/code&gt;, and key this in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.RatingLive.FormComponent do
  use ArcadeWeb, :live_component
  alias Arcade.Survey
  alias Arcade.Survey.Rating
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is simple enough, to begin with. We define our module, use the &lt;code&gt;:live_component&lt;/code&gt; behaviour, and add in some aliases that we&amp;#39;ll need later.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll use LiveView&amp;#39;s &lt;code&gt;.form/1&lt;/code&gt; function (more on that in a bit) to construct the rating form. This function requires a changeset, so we&amp;#39;ll need to store one in our component&amp;#39;s state. Here&amp;#39;s where the component lifecycle comes into play. When we render a live component, LiveView starts the component in the parent view&amp;#39;s process and calls these callbacks, in order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;mount/1&lt;/code&gt;
: The single argument is the socket, and we use this callback to set the initial state. This callback is invoked only once, when the component is first rendered from the parent live view.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;update/2&lt;/code&gt;
: The two arguments are the assigns argument given to &lt;code&gt;live_component/3&lt;/code&gt; and the socket. By default, it merges the assigns argument into the &lt;code&gt;socket.assigns&lt;/code&gt; established in &lt;code&gt;mount/1&lt;/code&gt;. We&amp;#39;ll use this callback to add additional content to the socket &lt;em&gt;each time &lt;code&gt;live_component/3&lt;/code&gt; is called&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;render/1&lt;/code&gt;
: The one argument is &lt;code&gt;socket.assigns&lt;/code&gt;. It works like a render in any other live view.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stateful components will always follow this process when first mounted and rendered. Then, when the component updates in response to changes in the parent live view, only the &lt;code&gt;update/2&lt;/code&gt; and &lt;code&gt;render/1&lt;/code&gt; callbacks fire. Since these updates skip the &lt;code&gt;mount/1&lt;/code&gt; callback, the &lt;code&gt;update/2&lt;/code&gt; function is the safest place to establish the component&amp;#39;s initial state. Let&amp;#39;s create our component&amp;#39;s &lt;code&gt;update/2&lt;/code&gt; function now, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def update(assigns, socket) do
  {:ok,
    socket
    |&amp;gt; assign(assigns)
    |&amp;gt; assign_rating()
    |&amp;gt; assign_changeset()}
end

def assign_rating(
    %{assigns: %{current_user: user, game: game}} = socket) do
  assign(socket, :rating, %Rating{user_id: user.id, game_id: game.id})
end

def assign_changeset(%{assigns: %{rating: rating}} = socket) do
  assign(socket, :changeset, Survey.change_rating(rating))
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These reducer functions will add the necessary keys to our &lt;code&gt;socket.assigns&lt;/code&gt;. They&amp;#39;ll drop in any &lt;code&gt;assigns&lt;/code&gt; our parent sends, add a new &lt;code&gt;Rating&lt;/code&gt; struct, and finally establish a changeset for the new rating.&lt;/p&gt;
&lt;p&gt;There are no surprises here. One reducer builds a new rating, and the other uses the &lt;code&gt;Survey&lt;/code&gt; context to build a changeset for that rating. Now, on to render.&lt;/p&gt;
&lt;p&gt;With our socket established, we&amp;#39;re ready to render. We&amp;#39;ll choose a template to keep our markup code neatly compartmentalized. Create a file, &lt;code&gt;lib/arcade_web/live/rating_live/form.html.heex&lt;/code&gt;. Add the game title markup followed by the game rating form shown here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;div class=&amp;quot;survey-component-container&amp;quot;&amp;gt;
  &amp;lt;section class=&amp;quot;row&amp;quot;&amp;gt;
  &amp;lt;h4&amp;gt;&amp;lt;%= @game.name %&amp;gt;&amp;lt;/h4&amp;gt;
  &amp;lt;/section&amp;gt;
  &amp;lt;section class=&amp;quot;row&amp;quot;&amp;gt;
    &amp;lt;.form
      let={f}
      for={@changeset}
      phx-change=&amp;quot;validate&amp;quot;
      phx-submit=&amp;quot;save&amp;quot;
      phx_target={@myself}
      id={@id}&amp;gt;

      &amp;lt;%= label f, :stars%&amp;gt;
      &amp;lt;%= select f, :stars, Enum.reverse(1..5) %&amp;gt;
      &amp;lt;%= error_tag f, :stars %&amp;gt;

      &amp;lt;%= hidden_input f, :user_id%&amp;gt;
      &amp;lt;%= hidden_input f, :game_id%&amp;gt;

      &amp;lt;%= submit &amp;quot;Save&amp;quot;, phx_disable_with: &amp;quot;Saving...&amp;quot; %&amp;gt;
    &amp;lt;/.form&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The form template is really just a standard Phoenix form, although the syntax for rendering the form may be new to you. The main function in the template is the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Helpers.html#form/1&quot;&gt;&lt;code&gt;form/1&lt;/code&gt;&lt;/a&gt; function: a function component made available by LiveView under the hood. The form function component returns a rendered HEEx template containing an HTML form built with the help of &lt;code&gt;Phoenix.HTML.Form.form_for/4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re feeling adventurous, you can &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view/blob/v0.17.5/lib/phoenix_live_view/helpers.ex#L1002&quot;&gt;check out the source code for the form function component&lt;/a&gt;. For now, all you really need to know is that calling &lt;code&gt;form/1&lt;/code&gt; returns an HTML form for the specified changeset, with the specified LiveView bindings. Let&amp;#39;s take a closer look at how our form is rendered.&lt;/p&gt;
&lt;p&gt;Since the &lt;code&gt;form/1&lt;/code&gt; function is built on top of the &lt;code&gt;form_for/4&lt;/code&gt; function, it presents a similar API. Here, we&amp;#39;re generating a form for the &lt;code&gt;@changeset&lt;/code&gt; assignment that was put in assigns via the &lt;code&gt;update/2&lt;/code&gt; callback.&lt;/p&gt;
&lt;p&gt;Then, we bind two events to the form, a &lt;code&gt;phx-change&lt;/code&gt; to send a &lt;code&gt;validate&lt;/code&gt; event and a &lt;code&gt;phx-submit&lt;/code&gt; to send a &lt;code&gt;save&lt;/code&gt; event. We target our form component to receive events by setting &lt;code&gt;phx-target&lt;/code&gt; to &lt;code&gt;@myself&lt;/code&gt;, and we tack on an &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that we&amp;#39;ve set a dynamic HTML id of the stateful component id, stored in socket assigns as &lt;code&gt;@id&lt;/code&gt;. This is because the game rating form will appear multiple times on the page, once for each game, and we need to ensure that each form gets a unique id. You&amp;#39;ll see how we set the &lt;code&gt;id&lt;/code&gt; assigns for the component when we render it in a bit.&lt;/p&gt;
&lt;p&gt;Our form has a &lt;code&gt;stars&lt;/code&gt; field with a label and error tag and a hidden field for each &lt;code&gt;user&lt;/code&gt; and &lt;code&gt;game&lt;/code&gt; relationship. We tie things up with a submit button.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll come back to the events a bit later. For now, let&amp;#39;s fold our work into the &lt;code&gt;RatingLive.Index.list/1&lt;/code&gt; function component.&lt;/p&gt;
&lt;h3&gt;Render the Component&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt; function component should render the rating form component if no rating for the given game and user exists. Let&amp;#39;s do that now.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def list(assigns) do
  ~H&amp;quot;&amp;quot;&amp;quot;
  &amp;lt;%= for {game, index} &amp;lt;- Enum.with_index(@games) do %&amp;gt;
    &amp;lt;%= if rating = List.first(game.ratings) do %&amp;gt;
      &amp;lt;Show.stars rating={rating} game={game} /&amp;gt;
    &amp;lt;% else %&amp;gt;
      &amp;lt;.live_component module={RatingLive.Form}
                        id={&amp;quot;rating-form-#{game.id}&amp;quot;}
                        game={game}
                        game_index={index}
                        current_user={@current_user } /&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;quot;&amp;quot;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we call on the component with the &lt;code&gt;live_component/1&lt;/code&gt; function, passing the user and game into the component as assigns, along with the game&amp;#39;s index in the &lt;code&gt;@games&lt;/code&gt; assignment. We add an &lt;code&gt;:id&lt;/code&gt;, a requirement of all stateful components. Since we&amp;#39;ll only have one rating per component, our &lt;code&gt;id&lt;/code&gt; with an embedded &lt;code&gt;game.id&lt;/code&gt; should be unique.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;live_component/1&lt;/code&gt; function is a function component made available to us by the LiveView framework. It takes in an argument of some assigns and returns a HEEx template that renders the given component within the parent live view. When using &lt;code&gt;live_component/1&lt;/code&gt; to render a live component, you must specify an assigns of &lt;code&gt;module&lt;/code&gt;, pointing to the name of the live component module to mount and render, and an assigns of &lt;code&gt;id&lt;/code&gt;, which LiveView will use to keep track of the component. Also, note the &lt;code&gt;{}&lt;/code&gt; interpolation syntax we&amp;#39;re using — this syntax is required when interpolating within HTML or HEEx tags.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s been a while since we&amp;#39;ve looked at things in the browser — but now, if you point your browser at &lt;code&gt;/survey&lt;/code&gt;, you should see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-01/ratings-forms.png&quot; alt=&quot;ratings forms&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;Handle Component Events&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ve bound events to save and validate our form, so we should teach our component how to do both. We need one &lt;code&gt;handle_event/2&lt;/code&gt; function head for each of the &lt;code&gt;save&lt;/code&gt; and &lt;code&gt;validate&lt;/code&gt; events. Let&amp;#39;s start with &lt;code&gt;validate&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(&amp;quot;validate&amp;quot;, %{&amp;quot;rating&amp;quot; =&amp;gt; rating_params}, socket) do
  {:noreply, validate_rating(socket, rating_params)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to build the reducer next:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def validate_rating(socket, rating_params) do
  changeset =
    socket.assigns.rating
    |&amp;gt; Survey.change_rating(rating_params)
    |&amp;gt; Map.put(:action, :validate)

  assign(socket, :changeset, changeset)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our &lt;code&gt;validate_rating/2&lt;/code&gt; reducer function validates the changeset and returns a new socket with the validated changeset (containing any errors) in socket assigns. This will cause the component to re-render the template with the updated changeset, allowing the &lt;code&gt;error_tag&lt;/code&gt; helpers in our &lt;code&gt;form_for&lt;/code&gt; form to render any errors.&lt;/p&gt;
&lt;p&gt;Next up, we&amp;#39;ll implement a &lt;code&gt;handle_event/2&lt;/code&gt; function that matches the &lt;code&gt;save&lt;/code&gt; event:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(&amp;quot;save&amp;quot;, %{&amp;quot;rating&amp;quot; =&amp;gt; rating_params}, socket) do
  {:noreply, save_rating(socket, rating_params)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&amp;#39;s the reducer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def save_rating(
         %{assigns: %{product_index: product_index, product: product}} = socket,
         rating_params
       ) do
  case Survey.create_rating(rating_params) do
    {:ok, rating} -&amp;gt;
      product = %{product | ratings: [rating]}
      send(self(), {:created_rating, product, product_index})
      socket

    {:error, %Ecto.Changeset{} = changeset} -&amp;gt;
      assign(socket, changeset: changeset)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we attempt to save the form. On failure, we assign a new changeset. On success, we send a message to the parent live view to do the heavy lifting for us. Then, as all handlers must do, we return the socket.&lt;/p&gt;
&lt;h3&gt;Update the Rating Index&lt;/h3&gt;
&lt;p&gt;What should happen when the game rating successfully saves? The &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt; function should no longer render the form for that game. Instead, the survey should display the saved rating. This kind of state change is squarely the responsibility of &lt;code&gt;SurveyLive&lt;/code&gt;. Our message will serve to notify the parent live view to change.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the interesting bit. All the parent needs to do is update the socket. The &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt; function already renders the right thing based on the content of the assigns that it receives from the parent, &lt;code&gt;SurveyLive&lt;/code&gt;. All we need to do is implement a handler to deal with the &amp;quot;created rating&amp;quot; message.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/arcade_web/live/survey_live.ex
def handle_info({:created_rating, updated_product, product_index}, socket) do
  {:noreply, handle_rating_created(socket, updated_product, product_index)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use &lt;code&gt;handle_info&lt;/code&gt; so that the parent live view process, &lt;code&gt;SurveyLive&lt;/code&gt;, can respond to the message sent by the child component. Now, our reducer can take the appropriate action. Notice that the message we match has a message name, an updated game, &lt;em&gt;and&lt;/em&gt; its index in the &lt;code&gt;:games&lt;/code&gt; list. We can use that information to update the game list without going back to the database. We&amp;#39;ll implement the reducer below to do this work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_rating_created(
         %{assigns: %{products: products}} = socket,
         updated_product,
         product_index
       ) do

  socket
  |&amp;gt; put_flash(:info, &amp;quot;Rating submitted successfully&amp;quot;)
  |&amp;gt; assign(
    :products,
    List.replace_at(products, product_index, updated_product)
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;handle_rating_created/3&lt;/code&gt; reducer adds a flash message and updates the game list with its rating. This causes the template to re-render, passing this updated game list to &lt;code&gt;RatingLive.Index.games/1&lt;/code&gt;. That function component, in turn, knows just what to do with a game containing a rating by the given user — it will render that rating&amp;#39;s details instead of a rating form.&lt;/p&gt;
&lt;p&gt;Notice the lovely layering. In the parent live view layer, all we need to do is manage the list of games and ratings. All of the form handling and rating or demographic details go elsewhere.&lt;/p&gt;
&lt;p&gt;The end result of a submitted rating is an updated game list and a flash message. Submit a rating, and see what happens:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2022-01/rating-form-success.png&quot; alt=&quot;rating form success&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You just witnessed the power of components and LiveView.&lt;/p&gt;
&lt;h2&gt;Wrap Up: You&amp;#39;ve Built a Complex LiveView UI with Components&lt;/h2&gt;
&lt;p&gt;This post covered a lot of ground. You implemented a sophisticated UI composed from simple layers, all thanks to LiveView components. You can wrap up simple markup with function components, while live components allow you to maintain component state and respond to events. Meanwhile, HEEx templates and LiveView provide some nice semantics for rendering markup and both types of components.&lt;/p&gt;
&lt;p&gt;LiveView is growing fast — it&amp;#39;s responding to the community&amp;#39;s needs and providing even more ergonomic solutions for developing complex interactive single-page apps. Function components and HEEx are just some of the latest features that make LiveView even more enjoyable to use.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Pitfalls of Metaprogramming in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/11/16/pitfalls-of-metaprogramming-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/11/16/pitfalls-of-metaprogramming-in-elixir.html</id>
    <published>2021-11-16T00:00:00+00:00</published>
    <updated>2021-11-16T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the final part of our series on Metaprogramming, we&#039;ll look at three common pitfalls you might encounter when using macros in Elixir.</summary>
    <content type="html">&lt;p&gt;Welcome back to this final part of our four-part series on metaprogramming in Elixir.&lt;/p&gt;
&lt;p&gt;Previously, we explored the various applications of macros.&lt;/p&gt;
&lt;p&gt;In this part, we&amp;#39;ll delve into common pitfalls that you might encounter when
metaprogramming in Elixir.&lt;/p&gt;
&lt;h2&gt;Common Perils of Macros&lt;/h2&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/macros.html#write-macros-responsibly&quot;&gt;official
documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Macros should only be used as a last resort. Remember that explicit is better than implicit. Clear code is better than
concise code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While it may be tempting to use metaprogramming for everything, it may not always be the best option.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;/2021/10/26/how-to-use-macros-in-elixir.html&quot;&gt;Applications of Macros&lt;/a&gt; part of this series outlines the majority of use cases of macros.&lt;/p&gt;
&lt;p&gt;However, you should only use macros with great caution.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll be looking at these three common pitfalls to avoid when using macros:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Injecting unnecessary functions&lt;/li&gt;
&lt;li&gt;Over-injecting behavior&lt;/li&gt;
&lt;li&gt;Replacing regular functions&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#39;s kick off by looking at what happens if you inject unnecessary functions into modules with macros.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;These points are inspired by &lt;a href=&quot;https://pragprog.com/titles/cmelixir/metaprogramming-elixir/#resources&quot;&gt;Metaprogramming Elixir&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;1. Injecting Unnecessary Functions with Macros&lt;/h2&gt;
&lt;p&gt;While macros can be used to inject functions into a caller, there are times where this is unnecessary.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CalculatorTransformer do
  defmacro __using__(_) do
    quote do
      def add(a, b), do: a + b
      def subtract(a, b), do: a - b
      def multiply(a, b), do: a * b
      def divide(a, b), do: a / b
    end
  end
end

defmodule Hospital do
  use CalculatorTransformer

  def calculate_cost(suite, procedure) do
    add(suite * 20, multiply(procedure, 5))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We inject various calculator functions into &lt;code&gt;Hospital&lt;/code&gt; to eliminate the need for a module identifier.&lt;/p&gt;
&lt;p&gt;However, the use of &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;multiply&lt;/code&gt; now seem like they appear from thin air.&lt;/p&gt;
&lt;p&gt;The code loses its semantic meaning and becomes harder to understand for first-time readers.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;To preserve the semantic meaning of the code, define &lt;code&gt;CalculatorTransformer&lt;/code&gt; as a regular module. This module
can be &lt;code&gt;import&lt;/code&gt;ed into &lt;code&gt;Hospital&lt;/code&gt; to eliminate module identifiers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CalculatorTransformer do
  def add(a, b), do: a + b
  def subtract(a, b), do: a - b
  def multiply(a, b), do: a * b
  def divide(a, b), do: a / b
end

defmodule Hospital do
  import CalculatorTransformer

  def calculate_cost(suite, procedure) do
    add(suite * 20, multiply(procedure, 5))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As well as creating unnecessary functions, macros can also over-inject behavior into a module. Let&amp;#39;s explore what this means.&lt;/p&gt;
&lt;h2&gt;2. Macros Over-injecting Behavior&lt;/h2&gt;
&lt;p&gt;As Elixir injects macros into the callsite, behavior can be over-injected.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s go back to the example of &lt;code&gt;BaseWrapper&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;What if we left the parsing logic for &lt;code&gt;post?&lt;/code&gt; within the &lt;code&gt;__using__&lt;/code&gt; macro?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro __using__(opts) do
  quote location: :keep, bind_quoted: [opts: opts] do
    # ...

    def post?(url, body) do
      case post(url, body) do
        {:ok, %HTTPoison.Response{status_code: code, body: body}} when code in 200..299 -&amp;gt;
          {:ok, body}

        {:ok, %HTTPoison.Response{body: body}} -&amp;gt;
          IO.inspect(body)
          error = body |&amp;gt; Map.get(&amp;quot;error&amp;quot;, body |&amp;gt; Map.get(&amp;quot;errors&amp;quot;, &amp;quot;&amp;quot;))
          {:error, error}

        {:error, %HTTPoison.Error{reason: reason}} -&amp;gt;
          IO.inspect(&amp;quot;reason #{reason}&amp;quot;)
          {:error, reason}
      end
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are two issues with this approach:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;By testing &lt;code&gt;post?&lt;/code&gt;, you test the inheritor rather than &lt;code&gt;BaseWrapper&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As there are multiple inheritors of &lt;code&gt;BaseWrapper&lt;/code&gt; and the entire behavior of &lt;code&gt;post?&lt;/code&gt; is injected into the inheritor, we
have to test every inheritor individually.&lt;/p&gt;
&lt;p&gt;This ensures that any inheritor-specific behavior does not modify the behavior of &lt;code&gt;post?&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Failure to do so can lead to lower test coverage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ambiguous error reporting.&lt;/p&gt;
&lt;p&gt;Any run-time errors raised by &lt;code&gt;post?&lt;/code&gt; will be logged under the inheritor, not &lt;code&gt;BaseWrapper&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Therefore, leaving the entire behavior in &lt;code&gt;post?&lt;/code&gt; can create confusion.&lt;/p&gt;
&lt;p&gt;The original implementation of &lt;code&gt;BaseWrapper&lt;/code&gt; moves the bulk of the parsing behavior into the wrapper instead. This implementation is much neater, semantically more meaningful, and readable.&lt;/p&gt;
&lt;p&gt;This minimizes the two issues mentioned above, as:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When you test the core behavior of &lt;code&gt;post?&lt;/code&gt;, only &lt;code&gt;BaseWrapper.parse_post&lt;/code&gt; is tested — not every single inheritor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any errors from parsing will be logged under &lt;code&gt;BaseWrapper&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;location: :keep&lt;/code&gt; works in a similar fashion.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While we&amp;#39;ve used wrappers in our example of over-injecting behavior, this can equally apply to regular macros.&lt;/p&gt;
&lt;p&gt;A rule of thumb is to minimize the amount of behavior in a macro.
Once the necessary information/computations that require a macro have been accessed/performed, you should move the remaining behavior out of the macro.&lt;/p&gt;
&lt;p&gt;The final pitfall we&amp;#39;ll examine is the use of macros when regular functions suffice.&lt;/p&gt;
&lt;h2&gt;3. Macros Used in Place of Regular Functions&lt;/h2&gt;
&lt;p&gt;As powerful as they are, you don&amp;#39;t always need macros. In some cases, you can replace a macro&amp;#39;s behavior with a regular function.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say that behavior that does not require compile-time information (or a macro to perform computation) is placed in a
macro, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro double(x) do
    quote do
      doubled = unquote(x) * 2
      doubled
    end
  end
end

defmodule Baz do
  require Foo

  def execute do
    Foo.double(3)
  end
end

iex(1)&amp;gt; Baz.execute
6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;double&lt;/code&gt; could have easily been substituted for a regular function.&lt;/p&gt;
&lt;p&gt;Its behavior does not require compile-time information nor a macro for computation. It will be injected into &lt;code&gt;Baz&lt;/code&gt; and
evaluated when &lt;code&gt;execute&lt;/code&gt; is called, just like a regular function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  def double(x), do: x * 2
end

defmodule Baz do
  def execute, do: Foo.double(3)
end

iex(1)&amp;gt; Baz.execute
6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, defining &lt;code&gt;double&lt;/code&gt; as a macro does not pose any benefits over a regular function.&lt;/p&gt;
&lt;h2&gt;Metaprogramming in Elixir: Further Reading&lt;/h2&gt;
&lt;p&gt;We have finally come to the end of this investigation into metaprogramming in Elixir!&lt;/p&gt;
&lt;p&gt;Remember: with great power comes great responsibility. Misusing metaprogramming can come back to bite you,
so tread lightly.&lt;/p&gt;
&lt;p&gt;While this series has aimed to explain metaprogramming and its intricacies concisely, it is by no means the &amp;quot;bible&amp;quot;
on this topic.&lt;/p&gt;
&lt;p&gt;There are many wonderful resources you can use to learn more about metaprogramming in Elixir! Here are just a few:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Written guides&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.theerlangelist.com/article/macros_1&quot;&gt;Understanding Elixir Macros - The Erlangelist&lt;/a&gt;*&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elixir-lang.org/getting-started/meta/quote-and-unquote.html&quot;&gt;Official Elixir tutorial on metaprogramming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://elixirschool.com/en/lessons/advanced/metaprogramming/&quot;&gt;Metaprogramming by Elixir School&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://serokell.io/blog/elixir-metaprogramming&quot;&gt;Metaprogramming in Elixir - Serokell&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Books&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pragprog.com/titles/cmelixir/metaprogramming-elixir/&quot;&gt;Metaprogramming Elixir&lt;/a&gt;*&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Talks&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Bo48sQDb-hk&quot;&gt;ElixirConf 2017 - Don&amp;#39;t Write Macros But Do Learn How They Work by Jesse Anderson&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(* - *highly recommended*)&lt;/p&gt;
&lt;p&gt;Thanks for reading, and see you next time!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Authorization and Policy Scopes for Phoenix Apps</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/11/02/authorization-and-policy-scopes-for-phoenix-apps.html"/>
    <id>https://blog.appsignal.com/2021/11/02/authorization-and-policy-scopes-for-phoenix-apps.html</id>
    <published>2021-11-02T00:00:00+00:00</published>
    <updated>2021-11-02T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how to implement quick and easy authorization for your Phoenix apps.</summary>
    <content type="html">&lt;p&gt;Authorization (not to be confused with authentication) is vital to every application but often isn&amp;#39;t given much thought before implementation. The &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc2196&quot;&gt;IETF Site Security Handbook&lt;/a&gt; defines authorization as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The process of granting privileges to processes and, ultimately, users. This differs from authentication in that authentication is the process used to identify a user. Once identified (reliably), the privileges, rights, property, and permissible actions of the user are determined by authorization.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, in short, authorization is about defining access policies and scoping.&lt;/p&gt;
&lt;p&gt;For example, consider a platform like Github.
In very simple terms, it must handle which repositories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a particular user is allowed to read (this is policy scoping)&lt;/li&gt;
&lt;li&gt;the user is allowed to write to (authorization)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you come from the Rails world, you might be familiar with some gems that provide APIs to handle this, the most popular ones being &lt;a href=&quot;https://github.com/CanCanCommunity/cancancan&quot;&gt;cancancan&lt;/a&gt; and &lt;a href=&quot;https://github.com/varvet/pundit&quot;&gt;pundit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In today&amp;#39;s post, we&amp;#39;ll take a close look at the two critical components of authorization — access policies and scoping. I&amp;#39;ll show you how you can roll out your own solution for each in Phoenix and how to leverage the Bodyguard library for quick and easy authorization.&lt;/p&gt;
&lt;h2&gt;Authorization in Phoenix&lt;/h2&gt;
&lt;p&gt;There are two parts to authorization that we need to keep in mind:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Access policy — Is &lt;em&gt;this user&lt;/em&gt; allowed to perform &lt;em&gt;this&lt;/em&gt; operation on &lt;em&gt;this resource&lt;/em&gt;?&lt;/li&gt;
&lt;li&gt;Policy scope — &lt;em&gt;Which resources&lt;/em&gt; is &lt;em&gt;this user&lt;/em&gt; allowed to see?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While it is definitely possible to roll out something by hand, it usually makes sense not to reinvent the wheel if well-maintained and tested libraries are available.
&lt;a href=&quot;https://github.com/jarednorman/canada&quot;&gt;Canada&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/bodyguard/Bodyguard.html&quot;&gt;Bodyguard&lt;/a&gt; are two of the more popular ones that I have seen in the community.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s see what implementation might look like for our own solution and also with Bodyguard. We will use a CMS example similar to what the &lt;a href=&quot;https://hexdocs.pm/phoenix/contexts.html&quot;&gt;official Phoenix Context guide&lt;/a&gt; uses. This CMS allows users to create pages and share them with everyone. Only the author should be able to edit, update, or delete a page once created, but everyone else should see the page.&lt;/p&gt;
&lt;h2&gt;Implementing Access Policies&lt;/h2&gt;
&lt;p&gt;Getting back to our CMS example — when the user is on a page, we need an access policy that decides if the user is allowed to perform an action (say, &lt;code&gt;edit&lt;/code&gt;) on the page.&lt;/p&gt;
&lt;h3&gt;Roll Your Own Access Policy&lt;/h3&gt;
&lt;p&gt;The following is what the official Phoenix guide suggests. This is also what most of us would do, were we rolling out our own authorization solution:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS.PageController do
  plug :authorize_page when action in [:edit, :update, :delete]

  defp authorize_page(conn, _) do
    page = CMS.get_page!(conn.params[&amp;quot;id&amp;quot;])

    if conn.assigns.current_author.id == page.author_id do
      assign(conn, :page, page)
    else
      conn
      |&amp;gt; put_flash(:error, &amp;quot;You can&amp;#39;t modify that page&amp;quot;)
      |&amp;gt; redirect(to: Routes.cms_page_path(conn, :index))
      |&amp;gt; halt()
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The implementation is straightforward. We use the &lt;code&gt;:authorize_page&lt;/code&gt; plug for edit, update, or delete actions. In that plug, we allow the action only if the page&amp;#39;s author is the same as the current user. Otherwise, we redirect to an index page that shows an error.&lt;/p&gt;
&lt;h3&gt;Use Bodyguard&lt;/h3&gt;
&lt;p&gt;We can also implement an access policy using &lt;code&gt;Bodyguard.Policy&lt;/code&gt; behavior. Depending on the level of access scoping you need, this behavior could be placed on the controller or directly on the underlying context. I usually like to define a separate &lt;code&gt;Policy&lt;/code&gt; module to handle this and then delegate the methods from the behavior&amp;#39;s target:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS.Policy do
  @behaviour Bodyguard.Policy

  alias Hello.Accounts.User

  # Super Admins can do anything
  def authorize(_action, %User{role: :super_admin}, _params), do: true

  # Users can list/get/create anything
  def authorize(action, %User{role: :user}, _params) when action in ~w[index show create]a, do: true

  # Users can edit/update/delete own pages
  def authorize(action, %User{id: id, role: :user} = user, %{author_id: ^id})
    when action in ~w[update edit delete]a,
    do: true

   # Default blacklist
  def authorize(_action, _user, _params), do: false
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we see that we defined &lt;code&gt;authorize(action, user, params)&lt;/code&gt; that returns &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt; to permit (or not) the action on the resource. You can also get additional control on the error messages by returning &lt;code&gt;{:error, reason}&lt;/code&gt; instead of just &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The &lt;code&gt;Bodyguard.Policy&lt;/code&gt; behavior expects the callbacks to return:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:ok&lt;/code&gt; or &lt;code&gt;true&lt;/code&gt; to permit an action.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:error&lt;/code&gt;, &lt;code&gt;{:error, reason}&lt;/code&gt;, or &lt;code&gt;false&lt;/code&gt; to deny an action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, on the context or the controller, all you need is to delegate the &lt;code&gt;authorize&lt;/code&gt; method to our &lt;code&gt;Policy&lt;/code&gt; module and then call &lt;code&gt;Bodyguard.permit&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS.PageController do
  plug :authorize_page

  defp authorize_page(conn, _) do
    page = CMS.show(conn.params[&amp;quot;id&amp;quot;])

    case Bodyguard.permit(__MODULE__, action, user, page) do
      :ok -&amp;gt;
        assign(conn, :page, page)
      {:error, _reason} -&amp;gt;
        conn
        |&amp;gt; put_flash(:error, &amp;quot;You can&amp;#39;t access that page&amp;quot;)
        |&amp;gt; redirect(to: Routes.cms_page_path(conn, :index))
        |&amp;gt; halt()
    end
  end

  defdelegate authorize(action, user, params), to: Hello.CMS.Policy
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To authorize an action, we can call &lt;code&gt;Bodyguard.permit(Hello.CMS.PageController, action, user)&lt;/code&gt;.
&lt;code&gt;Bodyguard.permit/4&lt;/code&gt; also accepts passing a fourth argument&amp;#39;s authorization in the actual resource.
This form can be used to authorize actions performed on a single resource (for example, &lt;code&gt;update&lt;/code&gt; or &lt;code&gt;delete&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Under the hood, &lt;code&gt;Bodyguard.permit&lt;/code&gt; calls &lt;code&gt;authorize&lt;/code&gt; on the module we provided as the first argument.
The return value is then normalized into &lt;code&gt;:ok&lt;/code&gt; or &lt;code&gt;{:error, reason}&lt;/code&gt; (regardless of whether we were returning &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;:ok&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;/&lt;code&gt;:error&lt;/code&gt;/&lt;code&gt;{:error, reason}&lt;/code&gt; from that method).&lt;/p&gt;
&lt;p&gt;While delegating &lt;code&gt;authorize&lt;/code&gt; from the controller works well, there might be cases when you need similar access control in multiple places. For example, the same resource could be accessed from your controller and through an &lt;a href=&quot;https://hexdocs.pm/absinthe/schemas.html&quot;&gt;Absinthe Resolver&lt;/a&gt; exposed through the GraphQL API.
For such cases, I suggest delegating &lt;code&gt;authorize/3&lt;/code&gt; on the Phoenix context module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS do
  # ...
  defdelegate authorize(action, user, params), to: Hello.CMS.Policy
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, when you need to call &lt;code&gt;Bodyguard.permit&lt;/code&gt; from your controller (or the Absinthe Resolver), pass in a first argument of that context module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS.PageController do
  defp authorize_page(conn, _) do
    page = CMS.show(conn.params[&amp;quot;id&amp;quot;])
    case Bodyguard.permit(CMS, action, user, page) do
      :ok -&amp;gt;
        # OK. Render page
      {:error, reason} -&amp;gt;
        # Error. Show flash and redirect
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is also very easy to write tests for the above policy. Here&amp;#39;s what the tests might look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;allows users to list pages&amp;quot; do
  user = Hello.Accounts.Fixtures.fixture(:user)
  assert :ok = Bodyguard.permit(Hello.CMS, :index, user)
end

test &amp;quot;allows user to update/delete own pages&amp;quot; do
  user = Hello.Accounts.Fixtures.fixture(:user)
  page = page_fixture(user)
  assert :ok = Bodyguard.permit(Hello.CMS, :update, user, page)
end

test &amp;quot;allows user to create pages&amp;quot; do
  user = Hello.Accounts.Fixtures.fixture(:user)
  assert :ok = Bodyguard.permit(Hello.CMS, :create, user)
end

test &amp;quot;does not allow user to update/delete pages of someone else&amp;quot; do
  user1 = Hello.Accounts.Fixtures.fixture(:user)
  user2 = Hello.Accounts.Fixtures.fixture(:user)

  page = page_fixture(user2)

  assert {:error, :unauthorized} = Bodyguard.permit(Hello.CMS, :update, user1, page)
end

test &amp;quot;allows super_admin to do anything&amp;quot; do
  super_admin = Hello.Accounts.Fixtures.fixture(:user_super_admin)
  user = Hello.Accounts.Fixtures.fixture(:user)
  page = page_fixture(user)
  assert :ok = Bodyguard.permit(Hello.CMS, :index, super_admin)
  assert :ok = Bodyguard.permit(Hello.CMS, :create, super_admin)
  assert :ok = Bodyguard.permit(Hello.CMS, :update, super_admin, page)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Implementing Policy Scopes&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve now allowed users to access resources based on some attributes. The next part of the puzzle is to handle the listing of resources. As you might have noticed above, we are allowing users to list everything.&lt;/p&gt;
&lt;p&gt;But you might have specific business requirements on what a user can and can&amp;#39;t list. For example, in the Github example, users can only see public repositories and the repositories that they have access to (e.g., through their organization or team). Similarly, you could set a restriction that users see all published posts but only their own drafts in a CMS.&lt;/p&gt;
&lt;h3&gt;Roll Your Own Policy Scoping&lt;/h3&gt;
&lt;p&gt;This just boils down to using the correct queries based on the user and their access rights. For example, a simple implementation inside a context could look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS do
  def list_pages(%{id: id} = user) do
    Page
    |&amp;gt; where(author_id: ^id)
    |&amp;gt; or_where(state: :published)
    |&amp;gt; Repo.all()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is definitely possible to do this with simple Ecto queries on the accessor methods. However, it usually makes much more sense to centralize these kinds of domain requirements so that future developers don&amp;#39;t forget to include one of the requirements while adding a new feature.&lt;/p&gt;
&lt;h3&gt;Use Bodyguard&lt;/h3&gt;
&lt;p&gt;With Bodyguard, we can provide default scoping to query items that a user can access. Implement a &lt;code&gt;scope/3&lt;/code&gt; function inside an &lt;code&gt;Ecto.Schema&lt;/code&gt; module from the &lt;code&gt;@behaviour Bodyguard.Schema&lt;/code&gt;. The function should filter the &lt;code&gt;query&lt;/code&gt; down to only include the resources the user is allowed to access. You can also pass custom params when invoking the scoping to provide further filtering.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s how it looks in practice:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS.Page do
  use Ecto.Schema

  alias Hello.Accounts.User

  def scope(query, user, params) do
    scope_published(query, user, params)
  end

  # Signed in users can access published posts or their own posts (in any state)
  defp scope_published(query, %User{role: :user, id: id}, _params) do
    query
    |&amp;gt; where(author_id: ^id)
    |&amp;gt; or_where(state: :published)
  end

  # Super admins can access anything
  defp scope_published(query, %User{role: :super_admin}, _params), do: query

  # Anonymous users can access only published posts
  defp scope_published(query, _user, _params), do: query |&amp;gt; where(state: :published)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, this can then be used inside your context when querying. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hello.CMS do
  def list_pages(user) do
    Page
    |&amp;gt; Bodyguard.scope(user) # &amp;lt;-- defers to Page.scope/3
    |&amp;gt; Repo.all()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we need to add another listing of the pages later, we can simply use the same &lt;code&gt;Bodyguard.scope(query, user)&lt;/code&gt; call and know that everything will be appropriately scoped.&lt;/p&gt;
&lt;h2&gt;Authorization in Phoenix: Further Reading&lt;/h2&gt;
&lt;p&gt;In this post, we saw how to implement authorization in your Phoenix apps.
We focused on a simple CMS example to explore authorization with — and without — external libraries.&lt;/p&gt;
&lt;p&gt;I recommend &lt;a href=&quot;https://dockyard.com/blog/2017/08/01/authorization-for-phoenix-contexts&quot;&gt;Dockyard&amp;#39;s Authorization Considerations For Phoenix Contexts blog post&lt;/a&gt; for a more detailed look at rolling out your authorization solution.&lt;/p&gt;
&lt;p&gt;If you are looking for external libraries, &lt;a href=&quot;https://hexdocs.pm/bodyguard/Bodyguard.html&quot;&gt;check out Bodyguard&lt;/a&gt;.
I have been using it in production for a while and can vouch for its customizability in authorization. It stays out of the way when we don&amp;#39;t want it and also clarifies operations that would otherwise be scattered inside the context and controller methods.&lt;/p&gt;
&lt;p&gt;I hope you&amp;#39;ve found this a useful guide that&amp;#39;s inspired you to dive into policy scoping and authorization in Phoenix apps.&lt;/p&gt;
&lt;p&gt;Until next time, happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Use Macros in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/10/26/how-to-use-macros-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/10/26/how-to-use-macros-in-elixir.html</id>
    <published>2021-10-26T00:00:00+00:00</published>
    <updated>2021-10-26T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the third part of our metaprogramming series, we&#039;ll explore the applications of macros in Elixir.</summary>
    <content type="html">&lt;p&gt;Welcome back to this third part of our four-part series on metaprogramming in Elixir.&lt;/p&gt;
&lt;p&gt;Previously, we established the underlying behavior of macros.&lt;/p&gt;
&lt;p&gt;Now we will dive into the various applications of macros in Elixir using open-source Elixir libraries.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s go!&lt;/p&gt;
&lt;h2&gt;Using Macro Wrappers to Extend Elixir Module Behavior&lt;/h2&gt;
&lt;p&gt;Macros can extend module behavior by adding new functions through wrappers that behave similarly to &lt;a href=&quot;https://stackify.com/oop-concept-inheritance/&quot;&gt;inheritance in object-oriented programming (OOP)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To extend a module, we use &lt;code&gt;use&lt;/code&gt; — this is syntactic sugar that performs the following for us:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro __using__(opts) do
    quote do
      # Extend another module’s behavior here
    end
  end
end

defmodule Bar do
  use Foo
  # equivalent to calling these two expressions
  # require Foo
  # Foo.__using__([])
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;__using__&lt;/code&gt; callback macro extends the behavior of &lt;code&gt;Bar&lt;/code&gt;. It is injected into the callsite and expanded.&lt;/p&gt;
&lt;p&gt;We will be using the following terminology:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Wrapper&lt;/strong&gt; — a module that extends other modules like &lt;code&gt;Foo&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inheritor&lt;/strong&gt; — a module that &lt;code&gt;use&lt;/code&gt;s wrappers like &lt;code&gt;Bar&lt;/code&gt;, inheriting behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s design a wrapper.&lt;/p&gt;
&lt;p&gt;Say we are building a website that relies on several APIs to work. Assuming we use an HTTP client like
&lt;a href=&quot;https://hexdocs.pm/httpoison/HTTPoison.html&quot;&gt;HTTPoison&lt;/a&gt; and each API request has common configurations like
request/response data type, we can handle the API requests in three ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up each API request separately.&lt;/li&gt;
&lt;li&gt;Compose API requests by chaining functions that configure each request.&lt;/li&gt;
&lt;li&gt;Build a wrapper that automatically configures each API request per request.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While each of these approaches has its merits, we will focus on the last approach.&lt;/p&gt;
&lt;p&gt;HTTPoison offers a wrapper for building basic API wrappers through
&lt;a href=&quot;https://hexdocs.pm/httpoison/HTTPoison.Base.html#content&quot;&gt;HTTPoison.Base&lt;/a&gt;. It handles aspects of an API request like setting up the endpoint and parsing the request/response body.&lt;/p&gt;
&lt;p&gt;We will build another wrapper on top of this that will enable inheritors to achieve our business requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Parse all request/response bodies to/from JSON.&lt;/li&gt;
&lt;li&gt;Generate an API URL, given a base URL and an endpoint for the base URL.&lt;/li&gt;
&lt;li&gt;Configure the request headers to accept JSON and set the content type to JSON.&lt;/li&gt;
&lt;li&gt;Parse and handle response bodies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The wrapper should produce inheritors like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule DogWrapper do
  use BaseWrapper, base_url: &amp;quot;https://api.dogs.com&amp;quot;

  def upload(name, breed) do
    case post?(&amp;quot;upload&amp;quot;, %{&amp;quot;name&amp;quot; =&amp;gt; name, &amp;quot;breed&amp;quot; =&amp;gt; breed}) do
      {:ok, response} -&amp;gt; {:ok, response[&amp;quot;link&amp;quot;]}
      {:error, error} -&amp;gt; {:error, error}
    end
  end
end

defmodule CatWrapper do
  use BaseWrapper, base_url: &amp;quot;https://api.cats.com&amp;quot;

  def upload(name, breed, talkative) do
    case post?(&amp;quot;upload&amp;quot;, %{&amp;quot;name&amp;quot; =&amp;gt; name, &amp;quot;breed&amp;quot; =&amp;gt; breed, &amp;quot;talkative&amp;quot; =&amp;gt; talkative}) do
      {:ok, response} -&amp;gt; {:ok, response[&amp;quot;url&amp;quot;]}
      {:error, error} -&amp;gt; {:error, error}
    end
  end
end

defmodule AnimalLovers do
  def upload(:dog, name, breed) do
    case DogWrapper.upload(name, breed) do
      {:ok, link} -&amp;gt; redirect(link)
      {:error, error} -&amp;gt; redirect_error(error)
    end
  end

  def upload(:cat, name, breed, talkative) do
    case CatWrapper.upload(name, breed, talkative) do
      {:ok, link} -&amp;gt; redirect(link)
      {:error, error} -&amp;gt; redirect_error(error)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The inheritors do not contain any cumbersome API request logic. Instead, they focus on extracting data from the responses and executing the business logic.&lt;/p&gt;
&lt;p&gt;Additionally, the wrapper integrates a base URL into the API requests, so inheritors provide only the endpoint.&lt;/p&gt;
&lt;p&gt;Now we know what we want to accomplish, let’s build the wrapper.&lt;/p&gt;
&lt;p&gt;First, we define our wrapper, calling it &lt;code&gt;BaseWrapper&lt;/code&gt;. This module will define the &lt;code&gt;__using__&lt;/code&gt; callback.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;opts&lt;/code&gt; is a keyword list that will hold the &lt;code&gt;base_url&lt;/code&gt; of the inheritor, and it is bound to the quote.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;location&lt;/code&gt; option for &lt;code&gt;quote&lt;/code&gt; ensures that any errors will directly point to the line in the &lt;code&gt;BaseWrapper&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Any behavior defined in &lt;code&gt;quote&lt;/code&gt; will be injected into the inheritor.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BaseWrapper do
  defmacro __using__(opts) do
    quote location: :keep, bind_quoted: [opts: opts] do
      # behavior goes here
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we extend our inheritor to use the basic behavior from &lt;code&gt;HTTPoison.Base&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# quote
use HTTPoison.Base
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we want to retrieve the base URL from &lt;code&gt;opts&lt;/code&gt;. We do not need to unquote &lt;code&gt;opts&lt;/code&gt; as it was bound.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# quote
base_url = Keyword.get(opts, :base_url)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, we can begin configuring our wrapper using &lt;code&gt;HTTPoison.Base&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HTTPoison.Base&lt;/code&gt; defines several callbacks used to process requests and responses.&lt;/p&gt;
&lt;p&gt;We will override these callbacks to implement the behavior we want.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# quote
# Modify request headers to include necessary information about the API
def process_request_headers(headers) do
  h = [
    {&amp;quot;Accept&amp;quot;, &amp;quot;application/json&amp;quot;},
    {&amp;quot;Content-Type&amp;quot;, &amp;quot;application/json&amp;quot;}
  ]

  headers ++ h
end

# Generate the URL for the endpoint using a base URL received from the inheritor
def process_url(endpoint), do: URI.merge(URI.parse(unquote(base_url)), endpoint) |&amp;gt; to_string()

# Automatically encode request body to JSON
def process_request_body(body), do: Jason.encode!(body)

# Automatically decode request body from JSON
def process_response_body(body), do: Jason.decode!(body)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we want to parse responses from POST requests based on the HTTP status code of the response.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# quote
def post?(endpoint, body) do
  # post is available as we have used HTTPoison.Base which will perform the necessary imports for us
  # post receives only the endpoint of the request as process_url prepends the base URL already
  response = post(endpoint, body)
  # We defer the parsing of the response to a function within the BaseWrapper module.
  # Reasons for doing so will be discussed later
  BaseWrapper.parse_post(response)
end

# BaseWrapper
def parse_post({:ok, %HTTPoison.Response{status_code: code, body: body}})
    when code in 200..299 do
  {:ok, body}
end

def parse_post({:ok, %HTTPoison.Response{body: body}}) do
  IO.inspect(body)
  error = body |&amp;gt; Map.get(&amp;quot;error&amp;quot;, body |&amp;gt; Map.get(&amp;quot;errors&amp;quot;, &amp;quot;&amp;quot;))
  {:error, error}
end

def parse_post({:error, %HTTPoison.Error{reason: reason}}) do
  IO.inspect(&amp;quot;reason #{reason}&amp;quot;)
  {:error, reason}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting all this together, we have a module that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BaseWrapper do
  defmacro __using__(opts) do
    quote location: :keep, bind_quoted: [opts: opts] do
      use HTTPoison.Base

      base_url = Keyword.get(opts, :base_url)

      def process_request_headers(headers) do
        h = [
          {&amp;quot;Accept&amp;quot;, &amp;quot;application/json&amp;quot;},
          {&amp;quot;Content-Type&amp;quot;, &amp;quot;application/json&amp;quot;}
        ]

        headers ++ h
      end
      def process_url(endpoint), do: URI.merge(URI.parse(unquote(base_url)), endpoint) |&amp;gt; to_string()
      def process_request_body(body), do: Jason.encode!(body)
      def process_response_body(body), do: Jason.decode!(body)

      # Function injected at compile-time to parse and act on responses accordingly
      def post?(url, body) do
        response = post(url, body)
        BaseWrapper.parse_post(response)
      end
    end
  end

  def parse_post({:ok, %HTTPoison.Response{status_code: code, body: body}})
      when code in 200..299 do
    {:ok, body}
  end

  def parse_post({:ok, %HTTPoison.Response{body: body}}) do
    IO.inspect(body)
    error = body |&amp;gt; Map.get(&amp;quot;error&amp;quot;, body |&amp;gt; Map.get(&amp;quot;errors&amp;quot;, &amp;quot;&amp;quot;))
    {:error, error}
  end

  def parse_post({:error, %HTTPoison.Error{reason: reason}}) do
    IO.inspect(&amp;quot;reason #{reason}&amp;quot;)
    {:error, reason}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ve used macro wrappers to extend module behavior. Now, let&amp;#39;s focus our attention on performing batch imports using wrappers.&lt;/p&gt;
&lt;h2&gt;Batch Imports with Macro Wrappers&lt;/h2&gt;
&lt;p&gt;We can use wrappers to perform batch imports in inheritors.&lt;/p&gt;
&lt;p&gt;We can define a group of imports/aliases/requires that will be available during compile-time without performing the imports manually in the inheritor.&lt;/p&gt;
&lt;p&gt;This is useful when several inheritors require the same set of imports and is best illustrated in &lt;a href=&quot;https://github.com/HashNuke/hound/blob/master/lib/hound/helpers.ex&quot;&gt;Hound&lt;/a&gt; — a browser automation testing library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hound/helpers.ex
defmacro __using__([]) do
  quote do
    import Hound
    import Hound.Helpers.Cookie
    import Hound.Helpers.Dialog
    import Hound.Helpers.Element
    import Hound.Helpers.Navigation
    import Hound.Helpers.Orientation
    import Hound.Helpers.Page
    import Hound.Helpers.Screenshot
    import Hound.Helpers.SavePage
    import Hound.Helpers.ScriptExecution
    import Hound.Helpers.Session
    import Hound.Helpers.Window
    import Hound.Helpers.Log
    import Hound.Helpers.Mouse
    import Hound.Matchers
    import unquote(__MODULE__)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hound overrides &lt;code&gt;__using__&lt;/code&gt; to import a host of helper modules available to the inheritor.&lt;/p&gt;
&lt;p&gt;The inheritors are always going to be test suites written by other developers. It is convenient and easy to maintain imports through &lt;code&gt;use Hound.Helpers&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next up, wrappers can also override and dynamically generate functions. Let&amp;#39;s see how that works.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Macro Wrappers Define Functions to Override&lt;/h2&gt;
&lt;p&gt;Like a child class &lt;a href=&quot;https://www.geeksforgeeks.org/overriding-in-java/&quot;&gt;overrides&lt;/a&gt; a method in its parent class in OOP, wrappers can define some base behavior for functions and allow inheritors to override this behavior.&lt;/p&gt;
&lt;p&gt;This is achieved using &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Kernel.html#defoverridable/1&quot;&gt;&lt;code&gt;defoverridable&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Phoenix uses this to great effect by allowing inheritors of &lt;code&gt;Phoenix.Controller.Pipeline&lt;/code&gt; to override functions like &lt;code&gt;init&lt;/code&gt; and &lt;code&gt;call&lt;/code&gt; to include context-specific behavior.&lt;/p&gt;
&lt;p&gt;However, if a custom behavior isn&amp;#39;t necessary — i.e. the function is not overwritten — the base behavior will be used instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/phoenix/controller/pipeline.ex
defmacro __using__(opts) do
  quote bind_quoted: [opts: opts] do
    # ...

    @doc false
    def init(opts), do: opts

    @doc false
    def call(conn, action) when is_atom(action) do
      conn
      |&amp;gt; merge_private(
        phoenix_controller: __MODULE__,
        phoenix_action: action
      )
      |&amp;gt; phoenix_controller_pipeline(action)
    end

    @doc false
    def action(%Plug.Conn{private: %{phoenix_action: action}} = conn, _options) do
      apply(__MODULE__, action, [conn, conn.params])
    end

    defoverridable init: 1, call: 2, action: 2
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Macro Wrappers Dynamically Generate Functions&lt;/h3&gt;
&lt;p&gt;You can also use &lt;code&gt;unquote&lt;/code&gt; fragments to dynamically define an arbitrary number of functions. These functions are injected into a module during compile-time. This is especially useful when working with dynamic data or data that comes from an API.&lt;/p&gt;
&lt;p&gt;This article will focus on the former, as &lt;a href=&quot;https://pragprog.com/titles/cmelixir/metaprogramming-elixir/#resources&quot;&gt;Metaprogramming Elixir&lt;/a&gt; includes a wonderful example of dynamically defining functions for API responses under the &lt;code&gt;code/hub/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say we are building a script that reads a list of groceries and generates functions for each category. These functions will operate on each unique category and the items within it.&lt;/p&gt;
&lt;p&gt;For simplicity, each function will be the category&amp;#39;s name and print the contents of the category.&lt;/p&gt;
&lt;p&gt;The grocery list will use the following format — &lt;code&gt;&amp;lt;category&amp;gt;:&amp;lt;comma separated list&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// groceries.txt
dinner:carrots,potatoes,curry,chicken cubes
supplies:paper,pencils
school:folder,binder
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can read this file in an Elixir script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# groceries.exs
defmodule Groceries do
  @filename &amp;quot;groceries.txt&amp;quot;
  for line &amp;lt;- File.stream!(Path.join([__DIR__, @filename]), [], :line) do
    # line represents each line of the groceries list
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ve extracted the lines of groceries, now we can parse each line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# for
[category, rest] = line |&amp;gt; String.split(&amp;quot;:&amp;quot;) |&amp;gt; Enum.map(&amp;amp;String.trim(&amp;amp;1))
groceries = rest |&amp;gt; String.split(&amp;quot;,&amp;quot;) |&amp;gt; Enum.map(&amp;amp;String.trim(&amp;amp;1))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can define our dynamic functions.&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;unquote&lt;/code&gt; as an argument for &lt;code&gt;def&lt;/code&gt;. &lt;code&gt;def&lt;/code&gt; is also a macro, so expands the &lt;code&gt;unquote&lt;/code&gt; along with anything in its body during compilation. This is known as an &lt;em&gt;unquote fragment&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# for
def unquote(String.to_atom(category))() do
  readable_list = Enum.join(unquote(groceries), &amp;quot; and &amp;quot;)
  IO.puts(&amp;quot;Groceries in #{unquote(category)} include #{readable_list}&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting it all together, we get the following script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# groceries.exs
defmodule Groceries do
  @filename &amp;quot;groceries.txt&amp;quot;
  for line &amp;lt;- File.stream!(Path.join([__DIR__, @filename]), [], :line) do
    [category, rest] = line |&amp;gt; String.split(&amp;quot;:&amp;quot;) |&amp;gt; Enum.map(&amp;amp;String.trim(&amp;amp;1))
    groceries = rest |&amp;gt; String.split(&amp;quot;,&amp;quot;) |&amp;gt; Enum.map(&amp;amp;String.trim(&amp;amp;1))

    def unquote(String.to_atom(category))() do
      readable_list = Enum.join(unquote(groceries), &amp;quot; and &amp;quot;)
      IO.puts(&amp;quot;Groceries in #{unquote(category)} include #{readable_list}&amp;quot;)
    end
  end
end

iex(1)&amp;gt; Groceries.dinner
Groceries in dinner include carrots and potatoes and curry and chicken cubes
:ok
iex(2)&amp;gt; Groceries.school
Groceries in school include folder and binder
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s turn our attention to implementing domain-specific languages (DSLs) using macros.&lt;/p&gt;
&lt;h2&gt;Implement Domain-Specific Languages using Macros&lt;/h2&gt;
&lt;p&gt;Domain-Specific Languages (DSLs) are &amp;quot;computer language(s) specialized to a particular application domain.&amp;quot;&lt;/p&gt;
&lt;p&gt;DSLs can be built and used in Elixir to solve business requirements.&lt;/p&gt;
&lt;p&gt;As the &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/domain-specific-languages.html&quot;&gt;official DSL tutorial&lt;/a&gt; points out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You don’t need macros in order to have a DSL: every data structure and every function you define in your module is part of your Domain-specific language.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, we will cover a simple implementation of a DSL using macros to demonstrate how that would look.&lt;/p&gt;
&lt;p&gt;The simplest example of a DSL is from &lt;code&gt;ExUnit&lt;/code&gt;, a built-in testing framework (taken from the &lt;a href=&quot;https://hexdocs.pm/ex_unit/1.12/ExUnit.html&quot;&gt;ExUnit documentation&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule AssertionTest do
  use ExUnit.Case, async: true

  test &amp;quot;the truth&amp;quot; do
    assert true
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;test&lt;/code&gt; is a macro that registers a new test case.&lt;/p&gt;
&lt;p&gt;These test cases are collated using &lt;a href=&quot;https://elixir-lang.org/getting-started/module-attributes.html#as-temporary-storage&quot;&gt;accumulating module attributes&lt;/a&gt;. Then, when the test suite executes, all of the declared test cases are executed.&lt;/p&gt;
&lt;p&gt;You can find a simplified implementation and explanation of this DSL in the &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/domain-specific-languages.html#building-our-own-test-case&quot;&gt;official tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/absinthe/overview.html&quot;&gt;Absinthe&lt;/a&gt; — an implementation of the &lt;a href=&quot;https://graphql.org/&quot;&gt;GraphQL&lt;/a&gt;
specification — has a DSL for defining &lt;a href=&quot;https://hexdocs.pm/absinthe/schemas.html&quot;&gt;schemas&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/absinthe/schema/notation.ex
defmacro object(identifier, attrs, do: block) do
  {attrs, block} =
    case Keyword.pop(attrs, :meta) do
      {nil, attrs} -&amp;gt;
        {attrs, block}

      {meta, attrs} -&amp;gt;
        meta_ast =
          quote do
            meta unquote(meta)
          end

        block = [meta_ast, block]
        {attrs, block}
    end

  __CALLER__
  |&amp;gt; recordable!(:object, @placement[:object])
  |&amp;gt; record!(
    Schema.ObjectTypeDefinition,
    identifier,
    attrs |&amp;gt; Keyword.update(:description, nil, &amp;amp;wrap_in_unquote/1),
    block
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;object&lt;/code&gt; is a macro that generates the GraphQL schema.&lt;/p&gt;
&lt;p&gt;We define it as a macro because we&amp;#39;re accessing compile-time information through &lt;code&gt;__CALLER__&lt;/code&gt;, and we&amp;#39;re attempting to work with the module&amp;#39;s metadata. Defining it as a macro loads the schemas during compile-time.&lt;/p&gt;
&lt;p&gt;Even the &lt;a href=&quot;https://hexdocs.pm/phoenix/routing.html&quot;&gt;routing functions&lt;/a&gt; in Phoenix are a DSL.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://alchemist.camp/episodes/router-dsl&quot;&gt;Alchemist Camp&amp;#39;s &amp;#39;Creating a DSL for our router&amp;#39; video series&lt;/a&gt; explains how to implement a routing system similar to Phoenix&amp;#39;s.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s time to move on to Abstract Syntax Trees (ASTs): how they can be traversed and when to use prewalk vs. postwalk macros.&lt;/p&gt;
&lt;h2&gt;Traversing Abstract Syntax Trees (ASTs)&lt;/h2&gt;
&lt;p&gt;We &lt;a href=&quot;/2021/09/07/an-introduction-to-metaprogramming-in-elixir.html&quot;&gt;introduced ASTs in part one&lt;/a&gt; of this series. You can traverse an existing AST to extract information about — or modify — the structure of the AST to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improve performance&lt;/li&gt;
&lt;li&gt;Simplify the AST&lt;/li&gt;
&lt;li&gt;Perform computations based on the structure of the AST&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As the modification of ASTs is a niche process and context-dependent, we will focus on how traversal is performed rather than the specific application of traversal.&lt;/p&gt;
&lt;h2&gt;Going Back to the Roots of ASTs&lt;/h2&gt;
&lt;p&gt;Before we can understand the traversal of ASTs, we have to get to grips with the core data structure of ASTs.&lt;/p&gt;
&lt;p&gt;Source code is parsed into trees — data structures that house hierarchical tree data. They begin with a root node, followed by a set of sub-trees — children nodes.&lt;/p&gt;
&lt;p&gt;Each node includes a reference to its children. Each childless node is known as a leaf.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cs.cmu.edu/~clo/www/CMU/DataStructures/Lessons/lesson4_1.htm&quot;&gt;Read more about the tree data structure.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The figure below illustrates the basic anatomy of a tree:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/tree-structure.png&quot; alt=&quot;Tree data structure&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Order of Traversal in ASTs&lt;/h2&gt;
&lt;p&gt;Now that we know the underlying data structure of an AST, we can tackle the problem of traversing an AST/tree.&lt;/p&gt;
&lt;p&gt;Elixir uses &lt;a href=&quot;https://www.hackerearth.com/practice/algorithms/graphs/depth-first-search/tutorial/&quot;&gt;depth-first traversal&lt;/a&gt; in either &lt;a href=&quot;https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/&quot;&gt;pre-order or post-order&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Depth-first traversal follows a node down to its children recursively until reaching a leaf. The sibling of the node is moved to next, and the recursion repeats.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/depth-first-search.gif&quot; alt=&quot;Depth-first search of tree data structures&quot;/&gt;
&lt;em&gt;(Source: &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Depth-first-tree.svg&quot;&gt;Wikimedia Commons&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If we use our example, the nodes are visited in the following order: &lt;code&gt;1 -&amp;gt; 2 -&amp;gt; 3 -&amp;gt; 4 -&amp;gt; 5 -&amp;gt; 6 -&amp;gt; 7&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pre-order and post-order traversal refer to how depth-first traversal occurs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pre-order traversal starts from the root node and traverses depth-first through the AST until the right-most leaf is reached.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our tree, the nodes would be visited in the following order: &lt;code&gt;1 -&amp;gt; 2 -&amp;gt; 3 -&amp;gt; 4 -&amp;gt; 5 -&amp;gt; 6 -&amp;gt; 7&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Post-order traversal starts from the left-most leaf of each sub-tree and traverses in depth-first fashion until we reach the root node.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our tree, the nodes would be visited in the following order: &lt;code&gt;2 -&amp;gt; 4 -&amp;gt; 5 -&amp;gt; 7 -&amp;gt; 6 -&amp;gt; 3 -&amp;gt; 1&lt;/code&gt;. The traversal happens upwards towards the root node.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/&quot;&gt;Read more about orders of traversal on Geeks for Geeks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Regardless of the traversal order, the traversal occurs recursively until the &amp;quot;end condition&amp;quot; — i.e., right-most leaf for pre-order and root node for post-order.&lt;/p&gt;
&lt;p&gt;In Elixir, functions represent each type of traversal:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Macro.prewalk&lt;/code&gt; — performs depth-first, pre-order traversal&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Macro.postwalk&lt;/code&gt; — performs depth-first, post-order traversal&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Macro.traverse&lt;/code&gt; — performs depth-first traversal and both pre and post-order traversal on the AST&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By traversing the tree in a given order, we can extract information about the AST and use it to modify the AST.&lt;/p&gt;
&lt;p&gt;We define functions that will be executed recursively on every node during traversal. These functions are similar to &lt;code&gt;map&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The input is the currently visited node, while the output is a modified/untouched node.&lt;/p&gt;
&lt;h2&gt;Prewalk vs. Postwalk Macros&lt;/h2&gt;
&lt;p&gt;You might ask: &amp;quot;What is the benefit of using pre-order traversal over post-order traversal, and vice versa?&amp;quot;&lt;/p&gt;
&lt;p&gt;In most scenarios, there is no difference between the two as both will traverse the AST.&lt;/p&gt;
&lt;p&gt;However, you&amp;#39;ll have a preference for &lt;code&gt;postwalk&lt;/code&gt; or &lt;code&gt;prewalk&lt;/code&gt; if the operation is order-sensitive — i.e., if you require the traversal to start at the root node or the left-most leaf first.&lt;/p&gt;
&lt;p&gt;This may happen when the operation aims to match the first node (in order) against a given condition and only perform the operation on that node. We would rather have the traversal find the node quickly to operate as soon as possible.&lt;/p&gt;
&lt;p&gt;In this case, &lt;code&gt;prewalk&lt;/code&gt; is preferred over &lt;code&gt;postwalk&lt;/code&gt; if the node appears at the beginning of the AST.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Macro.prewalk(ast, fn
  {:match, [], args} -&amp;gt; foo(args)
  otherwise -&amp;gt; otherwise
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another consideration is unintended infinite recursion. Take this example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Macro.prewalk({:foo, [], [:bar]}, fn
  {:foo, [], _} -&amp;gt; {:foo, [], [{:foo, [], [:bar]}]}
  otherwise -&amp;gt; otherwise
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this &lt;code&gt;prewalk&lt;/code&gt;, the function matches any node that calls the &lt;code&gt;foo&lt;/code&gt; function and replaces it with a recursive call to &lt;code&gt;foo&lt;/code&gt;, with &lt;code&gt;foo&lt;/code&gt; as the argument.&lt;/p&gt;
&lt;p&gt;This will produce an infinite AST that, when converted to Elixir code, will look something like &lt;code&gt;foo(foo(foo(...)))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;prewalk&lt;/code&gt; is recursively executed on an AST — usually until it reaches the right-most leaf, indicating the AST&amp;#39;s end. However, as the AST expands infinitely in the above example, there will never be a right-most leaf, hence infinite recursion.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;postwalk&lt;/code&gt; instead avoids this issue as we simply replace the node once and move on upwards to the root node where the recursion will stop.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Macro.postwalk({:foo, [], [:bar]}, fn
  {:foo, [], _} -&amp;gt; {:foo, [], [{:foo, [], [:bar]}]}
  otherwise -&amp;gt; otherwise
end)

{:foo, [], [{:foo, [], [:bar]}]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, while the choice of &lt;code&gt;prewalk&lt;/code&gt; and &lt;code&gt;postwalk&lt;/code&gt; might not matter when an operation is not order-sensitive, &lt;code&gt;postwalk&lt;/code&gt; is preferred over &lt;code&gt;prewalk&lt;/code&gt; to avoid infinite recursion.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;traverse&lt;/code&gt; combines &lt;code&gt;prewalk&lt;/code&gt; and &lt;code&gt;postwalk&lt;/code&gt;, performing both together. This is useful when we want to traverse the AST in both orders.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elixir-ecto/ecto&quot;&gt;Ecto&lt;/a&gt; uses &lt;code&gt;prewalk&lt;/code&gt; to count the number of interpolations within a given expression.&lt;/p&gt;
&lt;p&gt;In this case, there isn&amp;#39;t a specific reason to choose &lt;code&gt;prewalk&lt;/code&gt; over &lt;code&gt;postwalk&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/ecto/query/builder.ex
def bump_interpolations(expr, params) do
  len = length(params)

  Macro.prewalk(expr, fn
    # The following expression matches a pinned variable which is what Ecto relies on for
    # interpolation
    {:^, meta, [counter]} when is_integer(counter) -&amp;gt; {:^, meta, [len + counter]}
    other -&amp;gt; other
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elixir-ecto/ecto/blob/74a85a99b6dc0fc4667876d5341ad4cafceaa9f6/lib/ecto/query/builder/dynamic.ex#L53&quot;&gt;Ecto&lt;/a&gt; also uses &lt;code&gt;postwalk&lt;/code&gt; to expand dynamic expressions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/ecto/query/builder/dynamic.ex
defp expand(query, %{fun: fun}, {binding, params, subqueries, count}) do
  {dynamic_expr, dynamic_params, dynamic_subqueries} = fun.(query)

  Macro.postwalk(dynamic_expr, {binding, params, subqueries, count}, fn
    {:^, meta, [ix]}, {binding, params, subqueries, count} -&amp;gt;
      case Enum.fetch!(dynamic_params, ix) do
        {%Ecto.Query.DynamicExpr{binding: new_binding} = dynamic, _} -&amp;gt;
          binding = if length(new_binding) &amp;gt; length(binding), do: new_binding, else: binding
          expand(query, dynamic, {binding, params, subqueries, count})

        param -&amp;gt;
          {{:^, meta, [count]}, {binding, [param | params], subqueries, count + 1}}
      end

    {:subquery, i}, {binding, params, subqueries, count} -&amp;gt;
      subquery = Enum.fetch!(dynamic_subqueries, i)
      ix = length(subqueries)
      {{:subquery, ix}, {binding, [{:subquery, ix} | params], [subquery | subqueries], count + 1}}

    expr, acc -&amp;gt;
      {expr, acc}
  end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another way you can change module behavior using macros is through compile-time hooks — let&amp;#39;s take a quick look at those.&lt;/p&gt;
&lt;h2&gt;Compile-time Hooks with Macros&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Module.html#module-compile-callbacks&quot;&gt;Compile-time hooks&lt;/a&gt; allow the compilation behavior of a module to be modified. Callbacks accompany these hooks.&lt;/p&gt;
&lt;p&gt;The two notable hooks to discuss are &lt;code&gt;@before_compile&lt;/code&gt; and &lt;code&gt;@after_compile&lt;/code&gt;. They are useful when we want to perform computation right before — or right after — module compilation.&lt;/p&gt;
&lt;p&gt;For now, let&amp;#39;s look at a basic set of examples for each hook.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;@before_compile&lt;/code&gt;, as the callback (&lt;code&gt;defmacro __before_compile__(env)&lt;/code&gt;) is called right before compilation, the callback must be declared in a separate module from where the hook references it.&lt;/p&gt;
&lt;p&gt;If the callback is declared in the same module, the macro will not compile in time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro __before_compile__(env) do
    IO.inspect(env)
    nil
  end
end

defmodule Bar do
  @before_compile Foo
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An exception to this behavior is when &lt;code&gt;Bar&lt;/code&gt; is an inheritor of &lt;code&gt;Foo&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro __using__(_) do
    quote do
      @before_compile unquote(__MODULE__)
    end
  end

  defmacro __before_compile__(env) do
    IO.inspect(env)
    nil
  end
end

defmodule Bar do
  use Foo
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, as &lt;code&gt;@before_compile&lt;/code&gt; is injected into &lt;code&gt;Bar&lt;/code&gt;, its callback is defined in &lt;code&gt;Foo&lt;/code&gt; (a different module). Since &lt;code&gt;use&lt;/code&gt; calls &lt;code&gt;require&lt;/code&gt;, it ensures that &lt;code&gt;Foo&lt;/code&gt; is compiled before &lt;code&gt;Bar&lt;/code&gt;. This means &lt;code&gt;Foo.__before_compile__/1&lt;/code&gt; is always available to &lt;code&gt;Bar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;@after_compile&lt;/code&gt;, there isn&amp;#39;t a need to declare the callback (&lt;code&gt;defmacro __after_compile__(env, bytecode)&lt;/code&gt;) in another module. This is because the module housing the callback is already compiled, so the callback is available.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  @after_compile __MODULE__

  def __after_compile__(env, _bytecode) do
    IO.inspect(env)
    nil
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another hook that is worth mentioning briefly is &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Module.html#module-on_definition-1&quot;&gt;&lt;code&gt;@on_definition&lt;/code&gt;&lt;/a&gt;, which invokes its callback whenever a function/macro is defined in the current module.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/v1.12.2/lib/ex_unit/lib/ex_unit/case.ex#L501&quot;&gt;ExUnit&lt;/a&gt; uses &lt;code&gt;@before_compile&lt;/code&gt; in a test suite to inject a final function — &lt;code&gt;__ex_unit__&lt;/code&gt; — to execute the test suites after they have been collated.&lt;/p&gt;
&lt;p&gt;This function must be injected right before compilation when all the test suites are collated.&lt;/p&gt;
&lt;p&gt;You may also wish to store a list of data across macro invocation, such as when &lt;code&gt;ExUnit&lt;/code&gt; collates test cases and invokes them all at once.&lt;/p&gt;
&lt;p&gt;This can be achieved using &lt;a href=&quot;https://elixir-lang.org/getting-started/module-attributes.html#as-temporary-storage&quot;&gt;module attributes&lt;/a&gt;. Let&amp;#39;s see that in action.&lt;/p&gt;
&lt;h2&gt;Module Attributes as Temporary Storage&lt;/h2&gt;
&lt;p&gt;When we set a module attribute to accumulate, any invocation of the module attribute will add the given value to the list, rather than overriding it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  Module.register_attribute(__MODULE__, :names, accumulate: true)
  @names &amp;quot;John&amp;quot;
  @names &amp;quot;Peter&amp;quot;

  def print, do: IO.inspect(@names)
end

iex(1)&amp;gt; Foo.print
[&amp;quot;Peter&amp;quot;, &amp;quot;John&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We may also want to accumulate values through a function call.&lt;/p&gt;
&lt;p&gt;This happens when the parent module first compiles, and then a secondary module updates the module attribute via a macro, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro add(name) do
    quote do
      @names unquote(name)
      :ok
    end
  end
end

defmodule Bar do
  require Foo
  import Foo

  Module.register_attribute(__MODULE__, :names, accumulate: true)

  add &amp;quot;john&amp;quot;
  add &amp;quot;henry&amp;quot;

  IO.inspect(@names) # This prints [&amp;quot;henry&amp;quot;, &amp;quot;john&amp;quot;] right after the module is done compiling
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Foo&lt;/code&gt; must compile first. The attribute has to be registered under &lt;code&gt;Bar&lt;/code&gt; before it can be used in a given module.&lt;/p&gt;
&lt;p&gt;The exception to this rule is &lt;code&gt;use&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro __using__(_) do
    quote do
      import Foo
      Module.register_attribute(__MODULE__, :names, accumulate: true)
    end
  end

  defmacro add(name) do
    quote do
      @names unquote(name)
      :ok
    end
  end
end

defmodule Bar do
  use Foo

  add &amp;quot;john&amp;quot;
  add &amp;quot;henry&amp;quot;

  IO.inspect(@names) # This prints [&amp;quot;henry&amp;quot;, &amp;quot;john&amp;quot;] right after the module is done compiling
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is how &lt;code&gt;ExUnit&lt;/code&gt; accumulates test cases and uses &lt;code&gt;@before_compile&lt;/code&gt; to inject a &amp;quot;run all test cases in test suite&amp;quot; function right before compilation, similar to something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Calculator do
  def add(a, b), do: a + b
  def subtract(a, b), do: a - b
end

defmodule TestCase do
  defmacro __using__(_) do
    quote do
      import TestCase
      Module.register_attribute(__MODULE__, :tests, accumulate: true)
      @before_compile unquote(__MODULE__)
    end
  end

  defmacro __before_compile__(_env) do
    # Inject a run function into the test case after all tests have been accumulated
    quote do
      def run do
        Enum.each @tests, fn test_name -&amp;gt;
          result = apply(__MODULE__, test_name, [])
          state = if result, do: &amp;quot;pass&amp;quot;, else: &amp;quot;fail&amp;quot;
          IO.puts &amp;quot;#{test_name} =&amp;gt; #{state}&amp;quot;
        end
      end
    end
  end

  defmacro test(description, do: body) do
    test_name = String.to_atom(description)
    quote do
      @tests unquote(test_name)
      def unquote(test_name)(), do: unquote(body)
    end
  end
end

defmodule CalculatorTest do
  use TestCase
  import Calculator

  test &amp;quot;add 1, 2 should return 3&amp;quot; do
    add(1, 2) == 3
  end

  test &amp;quot;subtract 5, 2 should not return 4&amp;quot; do
    subtract(5, 2) == 4
  end
end

CalculatorTest.run
&amp;quot;add 1, 2 should return 3&amp;quot; =&amp;gt; pass
&amp;quot;subtract 5, 2 should not return 4&amp;quot; =&amp;gt; fail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we&amp;#39;ll touch on deferring computation using macros.&lt;/p&gt;
&lt;h2&gt;Deferring Computation with Macros&lt;/h2&gt;
&lt;p&gt;Macros inject behavior into the callsite as-is and can be used to avoid immediate evaluation of an expression.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  def if?(condition, do: block, else: else_block) do
    case condition do
      true -&amp;gt; block
      false -&amp;gt; else_block
    end
  end
end

Foo.if? true do
  IO.puts(&amp;quot;Truth&amp;quot;)
else
  IO.puts(&amp;quot;False&amp;quot;)
end

&amp;quot;Truth&amp;quot;
&amp;quot;False&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we tried implementing the new &lt;code&gt;if&lt;/code&gt; using a regular function. However, the result is not what we expect — rather than only evaluating and printing &amp;quot;Truth&amp;quot;, both &amp;quot;Truth&amp;quot; and &amp;quot;False&amp;quot; are printed.&lt;/p&gt;
&lt;p&gt;This is because of the nature of a regular function: each block is evaluated immediately, so the &lt;code&gt;case&lt;/code&gt; will not work.&lt;/p&gt;
&lt;p&gt;If we use a macro instead, the macro has to be expanded first, generating an AST of the &lt;code&gt;case&lt;/code&gt; first and evaluating the &lt;code&gt;case&lt;/code&gt; accordingly. During this time, the condition is evaluated, before matching against the &lt;code&gt;case&lt;/code&gt;, and, finally, the appropriate block is evaluated.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;This example is borrowed from &lt;a href=&quot;https://pragprog.com/titles/cmelixir/metaprogramming-elixir/#resources&quot;&gt;Metaprogramming Elixir&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Macros in Elixir: A Powerful Tool, If Used Wisely&lt;/h2&gt;
&lt;p&gt;You can apply macros to many scenarios to extend an application&amp;#39;s behavior in ways that normal code cannot.&lt;/p&gt;
&lt;p&gt;However, macros are a double-edged sword — when misused, they can create confusion and muddy code&amp;#39;s readability and semantic meaning.&lt;/p&gt;
&lt;p&gt;In the final part of this metaprogramming series, we will delve into the common pitfalls you might encounter when working with macros in Elixir.&lt;/p&gt;
&lt;p&gt;Thanks for reading, and see you next time!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Do Live Uploads in Phoenix LiveView</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/10/12/how-to-do-live-uploads-in-phoenix-liveview.html"/>
    <id>https://blog.appsignal.com/2021/10/12/how-to-do-live-uploads-in-phoenix-liveview.html</id>
    <published>2021-10-12T00:00:00+00:00</published>
    <updated>2021-10-12T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how to do live file uploads with LiveView, so that you can easily build forms.</summary>
    <content type="html">&lt;p&gt;The LiveView framework supports all of the most common features that Single-Page Apps must offer their users, including multipart uploads. In fact, LiveView can give us highly interactive file uploads, right out of the box.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll add a file upload feature to an existing Phoenix LiveView application. Along the way, you&amp;#39;ll learn how to use LiveView to display upload progress and feedback while editing and saving uploaded files.&lt;/p&gt;
&lt;h2&gt;Setting Up the Image Upload Feature&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;The live upload examples that we&amp;#39;ll be looking at in this post are drawn from the &amp;quot;Forms and Changesets&amp;quot; chapter in my book, &lt;a href=&quot;https://pragprog.com/titles/liveview/programming-phoenix-liveview/&quot;&gt;Programming LiveView&lt;/a&gt;, co-authored with Bruce Tate. Check it out for an even deeper dive into LiveView forms and so much more.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this example, we have an online game store — Arcade — that allows users to browse and review products. Admins can access a product management interface to create, edit, and delete the products we offer our users. We&amp;#39;ll give admins the ability to upload a product image that is then stored in the database along with the given product. Let&amp;#39;s plan out our new image upload feature before we start writing any code.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll begin in our application core by adding an &lt;code&gt;image_upload&lt;/code&gt; field to the table and schema for products. Then, we&amp;#39;ll create a LiveView form component that supports file uploads. Finally, we&amp;#39;ll teach our component to report on upload progress and other bits of upload feedback.&lt;/p&gt;
&lt;p&gt;This post will focus on adding the live upload functionality to an existing LiveView app that already implements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A live view for displaying products.&lt;/li&gt;
&lt;li&gt;A LiveView component that contains a form for creating/editing products.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;#39;ll zero in on the code required to add the upload functionality to this form.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/2021/09/28/real-time-form-validations-with-phoenix-liveview.html&quot;&gt;Check out my earlier post for a basic introduction to working with forms in LiveView&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now we&amp;#39;re ready to write some code.&lt;/p&gt;
&lt;h2&gt;Persist Product Images in Phoenix LiveView&lt;/h2&gt;
&lt;p&gt;Assuming our Phoenix LiveView app already has a &lt;code&gt;products&lt;/code&gt; table and &lt;code&gt;Product&lt;/code&gt; schema, we&amp;#39;ll now update both to store an &lt;code&gt;image_upload&lt;/code&gt; attribute. This attribute will point to the location of the uploaded file. Once we have our backend wired up, we&amp;#39;ll be able to update the existing live view form to accommodate file uploads for a product.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll start at the database layer by generating a migration to add a field, &lt;code&gt;:image_upload&lt;/code&gt;, to the &lt;code&gt;products&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;First, generate your migration file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[arcade] ➔ mix ecto.gen.migration add_image_to_products
* creating priv/repo/migrations/20201231152152_add_image_to_products.exs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a migration file for us, &lt;code&gt;priv/repo/migrations/20201231152152_add_image_to_products.exs&lt;/code&gt;. Open up that file and key in the contents to the &lt;code&gt;change&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Arcade.Repo.Migrations.AddImageToProducts do
  use Ecto.Migration

  def change do
    alter table(:products) do
      add :image_upload, :string
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will add the new database field when we run the migration. Let&amp;#39;s do that now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[arcade] ➔ mix ecto.migrate

[info]  == Running 20201231152152 \

Arcade.Repo.Migrations.AddImageToProducts.change/0 forward
10:22:24.034 [info]  alter table products

10:22:24.041 [info]  == Migrated 20201231152152 in 0.0s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This migration added a new column — &lt;code&gt;:image_upload&lt;/code&gt; — of type &lt;code&gt;:string&lt;/code&gt; to the &lt;code&gt;products&lt;/code&gt; table, but our schema still needs attention.&lt;/p&gt;
&lt;p&gt;Update the corresponding &lt;code&gt;Product&lt;/code&gt; schema by adding the new &lt;code&gt;:image_upload&lt;/code&gt; field to the &lt;code&gt;schema&lt;/code&gt; function, which should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Arcade.Catalog.Product do
  use Ecto.Schema
  import Ecto.Changeset

  schema &amp;quot;products&amp;quot; do
    field :description, :string
    field :name, :string
    field :sku, :integer
    field :unit_price, :float
    field :image_upload, :string
    timestamps()
  end

  @doc false
  def changeset(product, attrs) do
    product
    |&amp;gt; cast(attrs, [:name, :description, :unit_price, :sku, :image_upload])
    |&amp;gt; validate_required([:name, :description, :unit_price, :sku])
    |&amp;gt; validate_number(:unit_price, greater_than: 0)
    |&amp;gt; unique_constraint(:sku)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember, the changeset &lt;code&gt;cast/4&lt;/code&gt; function must explicitly whitelist new fields, so make sure you add the &lt;code&gt;:image_upload&lt;/code&gt; attribute there, as shown above.&lt;/p&gt;
&lt;p&gt;Now that the changeset has an &lt;code&gt;:image_upload&lt;/code&gt; attribute, we can save product records that know their image upload location. With that in place, we can make an image upload field available in the &lt;code&gt;ProductLive.FormComponent&lt;/code&gt;&amp;#39;s form. We&amp;#39;re one step closer to giving users the ability to save products with images.&lt;/p&gt;
&lt;p&gt;Now, let&amp;#39;s turn our attention to the component.&lt;/p&gt;
&lt;h2&gt;How to Allow Live Uploads&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ll see our product changeset in action in a bit. First, we need to give the product form the ability to support file uploads. In our Phoenix application, both the &amp;quot;new product&amp;quot; and &amp;quot;edit product&amp;quot; pages use the &lt;code&gt;ProductLive.FormComponent&lt;/code&gt;. This provides one centralized place to maintain our product form. Changes to this component will enable users to upload an image for a new product and a product they are editing.&lt;/p&gt;
&lt;p&gt;To enable uploads for our component, or any live view, we need to call the &lt;code&gt;allow_upload/3&lt;/code&gt; function with a first argument of the socket. This will put the data into socket assigns that the LiveView framework will then use to perform file uploads. So, for a component, we&amp;#39;ll call &lt;code&gt;allow_upload/3&lt;/code&gt; when the component first starts up and establishes its initial state in the &lt;code&gt;update/2&lt;/code&gt; function. For a live view, we&amp;#39;d call &lt;code&gt;allow_upload/3&lt;/code&gt; in the &lt;code&gt;mount/3&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;allow_upload/3&lt;/code&gt; function is a reducer that takes in an argument of the socket, the upload name, and the upload options and returns an annotated socket. Supported options include file types, file size, number of files per upload name, and more. Let&amp;#39;s see it in action:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.ProductLive.FormComponent do
  use ArcadeWeb, :live_component
  alias Arcade.Product

  @impl true
  def update(%{product: product} = assigns, socket) do
    changeset = Product.changeset(product, %{})
    {:ok, socket
      |&amp;gt; assign(assigns)
      |&amp;gt; assign(:changeset, changeset)
      |&amp;gt; allow_upload(:image, accept: ~w(.jpg .jpeg .png), max_entries: 1)}
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;In &lt;code&gt;allow_upload/3&lt;/code&gt;, we pipe in a socket and specify a name for our upload: &lt;code&gt;:image&lt;/code&gt;. We also provide some options — the maximum number of permitted files and the accepted file formats.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at what our socket assigns looks like after &lt;code&gt;allow_upload/3&lt;/code&gt; is invoked:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%{
  # ...
  uploads: %{
    __phoenix_refs_to_names__: %{&amp;quot;phx-FlZ_j-hPIdCQuQGG&amp;quot; =&amp;gt; :image},
    image: #Phoenix.LiveView.UploadConfig&amp;lt;
      accept: &amp;quot;.jpg,.jpeg,.png&amp;quot;,
      entries: [],
      errors: [],
      max_entries: 1,
      max_file_size: 8000000,
      name: :image,
      progress_event: #Function&amp;lt;1.71870957/3 ...&amp;gt;,
      ref: &amp;quot;phx-FlZ_j-hPIdCQuQGG&amp;quot;,
      ...
    &amp;gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The socket now contains an &lt;code&gt;:uploads&lt;/code&gt; map that specifies the configuration for each upload field your live view allows. We allowed uploads for an upload called &lt;code&gt;:image&lt;/code&gt;. So our map contains a key of &lt;code&gt;:image&lt;/code&gt; pointing to a value of the configuration constructed using the options we gave &lt;code&gt;allow_upload/3&lt;/code&gt;. This means that we can add a file upload field called &lt;code&gt;:image&lt;/code&gt; to our form, and LiveView will track the progress of files uploaded via the field within &lt;code&gt;socket.assigns.uploads.image&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can call &lt;code&gt;allow_upload/3&lt;/code&gt; multiple times with different upload names, thus allowing any number of file uploads in a given live view or component. For example, you could have a form that allows a user to upload a main image, a thumbnail image, a hero image, and more.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve set up our uploads state, let&amp;#39;s take a closer look at the &lt;code&gt;:image&lt;/code&gt; upload configuration.&lt;/p&gt;
&lt;h3&gt;Upload Configurations in Phoenix LiveView&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;:image&lt;/code&gt; upload config looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#Phoenix.LiveView.UploadConfig&amp;lt;
  accept: &amp;quot;.jpg,.jpeg,.png&amp;quot;,
  entries: [],
  errors: [],
  max_entries: 1,
  max_file_size: 8000000,
  name: :image,
  progress_event: #Function&amp;lt;1.71870957/3 ...&amp;gt;,
  ref: &amp;quot;phx-FlZ_j-hPIdCQuQGG&amp;quot;,
  ...
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that it contains the configuration options we passed to &lt;code&gt;allow_upload/3&lt;/code&gt;: the accepted file types list and file formats.&lt;/p&gt;
&lt;p&gt;It also has an attribute called &lt;code&gt;:entries&lt;/code&gt;, which points to an empty list. When a user uploads a file for the &lt;code&gt;:image&lt;/code&gt; form field, LiveView will automatically update this list with the file upload entry as it completes.&lt;/p&gt;
&lt;p&gt;Similarly, the &lt;code&gt;:errors&lt;/code&gt; list starts out empty and is automatically populated by LiveView with any errors from an invalid file upload entry.&lt;/p&gt;
&lt;p&gt;In this way, the LiveView framework does the work of performing the file upload and tracking its state for you. We&amp;#39;ll see both of these attributes in action in a bit.&lt;/p&gt;
&lt;p&gt;Now that we&amp;#39;ve allowed uploads in our component, we&amp;#39;re ready to update the template with the file upload form field.&lt;/p&gt;
&lt;h2&gt;Render the File Upload Field&lt;/h2&gt;
&lt;p&gt;You&amp;#39;ll use the &lt;code&gt;Phoenix.LiveView.Helpers.live_file_input/2&lt;/code&gt; function to generate the HTML for a file upload form field. Here&amp;#39;s a look at our form component template:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= f = form_for @changeset, &amp;quot;#&amp;quot;,
          id: &amp;quot;product-form&amp;quot;,
          phx_target: @myself,
          phx_change: &amp;quot;validate&amp;quot;,
          phx_submit: &amp;quot;save&amp;quot; %&amp;gt;

  &amp;lt;%= label f, :name %&amp;gt;
  &amp;lt;%= text_input f, :name %&amp;gt;
  &amp;lt;%= error_tag f, :name %&amp;gt;

  &amp;lt;%= label f, :description %&amp;gt;
  &amp;lt;%= text_input f, :description %&amp;gt;
  &amp;lt;%= error_tag f, :description %&amp;gt;

  &amp;lt;%= label f, :unit_price %&amp;gt;
  &amp;lt;%= number_input f, :unit_price, step: &amp;quot;any&amp;quot; %&amp;gt;
  &amp;lt;%= error_tag f, :unit_price %&amp;gt;

  &amp;lt;%= label f, :sku %&amp;gt;
  &amp;lt;%= number_input f, :sku %&amp;gt;
  &amp;lt;%= error_tag f, :sku %&amp;gt;

  &amp;lt;% # File upload fields here: %&amp;gt;
  &amp;lt;%= label f, :image %&amp;gt;
  &amp;lt;%= live_file_input @uploads.image %&amp;gt;

  &amp;lt;%= submit &amp;quot;Save&amp;quot;, phx_disable_with: &amp;quot;Saving...&amp;quot; %&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the use of &lt;code&gt;live_file_input/2&lt;/code&gt; with an argument of &lt;code&gt;@uploads.image&lt;/code&gt;. Remember, &lt;code&gt;socket.assigns&lt;/code&gt; has a map of uploads. Here, we provide &lt;code&gt;@uploads.image&lt;/code&gt; to &lt;code&gt;live_file_input/2&lt;/code&gt; to create a form field with the right configuration and tie that form field to the correct part of socket state. This means that LiveView will update &lt;code&gt;socket.assigns.uploads.image&lt;/code&gt; with any new entries or errors that occur when a user uploads a file via this form input.&lt;/p&gt;
&lt;p&gt;The live view can present upload progress by displaying data from &lt;code&gt;@uploads.image.entries&lt;/code&gt; and &lt;code&gt;@uploads.image.errors&lt;/code&gt;. LiveView will handle all of the details of uploading the file and updating socket assigns &lt;code&gt;@uploads.image&lt;/code&gt; entries and errors for us. All we have to do is render the data that is stored in the socket. We&amp;#39;ll take that on soon.&lt;/p&gt;
&lt;p&gt;Now, we should be able to see the file upload field displayed in the browser like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/file-upload-field.png&quot; alt=&quot;file upload field&quot;/&gt;&lt;/p&gt;
&lt;p&gt;And if you inspect the element, you&amp;#39;ll see that the &lt;code&gt;live_file_input/2&lt;/code&gt; function generated the appropriate HTML:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/file-upload-button.png&quot; alt=&quot;file upload button&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/file-upload-html.png&quot; alt=&quot;file upload html&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can see that the generated HTML has the &lt;code&gt;accept=&amp;quot;.jpg,.jpeg,.png&amp;quot;&lt;/code&gt; attribute set, thanks to the options we passed to &lt;code&gt;allow_upload/3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;LiveView also supports drag-and-drop file uploads. All we have to do is add an element to the page with the &lt;code&gt;phx-drop-target&lt;/code&gt; attribute, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= f = form_for @changeset, &amp;quot;#&amp;quot;,
          id: &amp;quot;product-form&amp;quot;,
          phx_target: @myself,
          phx_change: &amp;quot;validate&amp;quot;,
          phx_submit: &amp;quot;save&amp;quot; %&amp;gt;

  # ...

  &amp;lt;div phx-drop-target=&amp;quot;&amp;lt;%= @uploads.image.ref %&amp;gt;&amp;quot;&amp;gt;
    &amp;lt;%= live_file_input @uploads.image %&amp;gt;
  &amp;lt;/div

  # ...
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We give the attribute a value of &lt;code&gt;@uploads.image.ref&lt;/code&gt;. This socket assignment is the ID that LiveView JavaScript uses to identify the file upload form field and tie it to the correct key in &lt;code&gt;socket.assigns.uploads&lt;/code&gt;. So now, if a user clicks the &amp;quot;choose file&amp;quot; button &lt;em&gt;or&lt;/em&gt; drags-and-drops a file into the area of this &lt;code&gt;div&lt;/code&gt;, LiveView will store the file info in the &lt;code&gt;socket.assigns.uploads&lt;/code&gt; assignment, under the name of the specified upload, in that upload&amp;#39;s &lt;code&gt;:entries&lt;/code&gt; list.&lt;/p&gt;
&lt;p&gt;As with other form interactions, LiveView automatically handles the client/server communication. When the user submits the form, LiveView&amp;#39;s JavaScript will first upload the file(s) and then invoke the &lt;code&gt;handle_event/3&lt;/code&gt; callback for the form&amp;#39;s &lt;code&gt;phx-submit&lt;/code&gt; event. To process the file upload, this event handler will need to consume the file upload stored in &lt;code&gt;socket.assigns.uploads.image.entries&lt;/code&gt;. Let&amp;#39;s do that now.&lt;/p&gt;
&lt;h2&gt;Consume Uploaded Entries&lt;/h2&gt;
&lt;p&gt;Our &lt;code&gt;handle_event/3&lt;/code&gt; function for the &lt;code&gt;phx_submit: &amp;quot;save&amp;quot;&lt;/code&gt; form event will use LiveView&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#consume_uploaded_entry/3&quot;&gt;&lt;code&gt;consume_uploaded_entry/3&lt;/code&gt;&lt;/a&gt; function to process the uploaded file. For now, we&amp;#39;ll have our function write the uploaded file to our app&amp;#39;s static assets in &lt;code&gt;priv/static/images&lt;/code&gt;. This is so that we can display it on the product show template later on.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s our code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.ProductLive.FormComponent do
# ...
  def handle_event(&amp;quot;save&amp;quot;, product_params, socket) do
    file_path =
      consume_uploaded_entry(socket, :image, fn %{path: path}, _entry -&amp;gt;
        dest = Path.join(&amp;quot;priv/static/uploads&amp;quot;, Path.basename(path))
        File.cp!(path, dest)
        Routes.static_path(socket, &amp;quot;/uploads/#{Path.basename(dest)}&amp;quot;)
      end)

    product = save_product(Map.put(product_params, :image_upload, file_path)

    {:noreply,
      socket
      |&amp;gt; push_redirect(to: Routes.product_show_path(socket, :show, product))}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We save the image to static assets and return the file path from &lt;code&gt;consume_uploaded_entry/3&lt;/code&gt;. Then, we call a helper function — &lt;code&gt;save_product/1&lt;/code&gt; (not pictured here) — to update the product with the given form params, including the new &lt;code&gt;:image_upload&lt;/code&gt; attribute set to our new file path. Finally, we redirect to the Product Show page.&lt;/p&gt;
&lt;p&gt;To see our code in action, let&amp;#39;s add some markup to the product show template to display image uploads. Then, we&amp;#39;ll try out our feature.&lt;/p&gt;
&lt;h3&gt;Display Image Uploads&lt;/h3&gt;
&lt;p&gt;Open up &lt;code&gt;lib/arcade_web/live/product_live/show.html.leex&lt;/code&gt; and add the following markup to display the uploaded image or a fallback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;article class=&amp;quot;column&amp;quot;&amp;gt;
   &amp;lt;img
      alt=&amp;quot;product image&amp;quot; width=&amp;quot;200&amp;quot; height=&amp;quot;200&amp;quot;
      src=&amp;quot;&amp;lt;%=Routes.static_path(
              @socket,
              @product.image_upload || &amp;quot;/images/default-thumbnail.jpg&amp;quot;)%&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;/article&amp;gt;
&amp;lt;!-- product details... --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Perfect. Now, we can test drive it. Visit &lt;code&gt;/products/1/edit&lt;/code&gt; and upload a file:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/edit-product-image.png&quot; alt=&quot;edit product image&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Once you submit the form, you&amp;#39;ll see the show page render the newly uploaded image, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/product-show-image.png&quot; alt=&quot;product show image&quot;/&gt;&lt;/p&gt;
&lt;p&gt;We did it! The LiveView framework handled all of the client/server communication details that make the page interactive. LiveView performed the file upload for you and made responding to upload events easy and customizable. You only needed to tell the live view which uploads to track and what to do with uploaded files when the form is submitted. Then you added the file upload form field to the page with the view helper and LiveView handled the rest!&lt;/p&gt;
&lt;p&gt;There&amp;#39;s one last thing to do. Earlier, I promised &lt;em&gt;reactive&lt;/em&gt; file uploads that share feedback with the user. Let&amp;#39;s take a look at this now.&lt;/p&gt;
&lt;h2&gt;Display Upload Feedback in Phoenix LiveView Forms&lt;/h2&gt;
&lt;p&gt;We know that LiveView automatically updates the &lt;code&gt;:entries&lt;/code&gt; and &lt;code&gt;:errors&lt;/code&gt; lists in the uploads config portion of &lt;code&gt;socket.assigns&lt;/code&gt; once the upload begins. Let&amp;#39;s display this information in the template to give the user real-time progress tracking. The code is amazingly simple. We&amp;#39;ll iterate over &lt;code&gt;@uploads.image.entries&lt;/code&gt; to display the progress for each entry:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= for entry &amp;lt;- @uploads.image.entries do %&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;progress value={entry.progress} max=&amp;quot;100&amp;quot;&amp;gt; &amp;lt;%= entry.progress %&amp;gt;% &amp;lt;/progress&amp;gt;
  &amp;lt;/p&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use the &lt;a href=&quot;https://www.w3schools.com/tags/tag_progress.asp&quot;&gt;HTML progress tag&lt;/a&gt; to create a simple progress bar that is populated with the progress of our file upload in real-time. As LiveView&amp;#39;s JavaScript is uploading the file for you, LiveView is updating the value of the entry&amp;#39;s progress in socket assigns. This causes the relevant portion of the template to re-render, thereby showing the updated progress bar in real-time. LiveView handles the work of tracking the changes to the image entry&amp;#39;s progress. All we have to do is display it.&lt;/p&gt;
&lt;p&gt;You can use a similar approach to iterate over and display any errors stored in &lt;code&gt;@uploads.image.errors&lt;/code&gt;. You won&amp;#39;t have to do any work to validate files and populate errors. LiveView handles those details. All you need to do is display any errors based on the needs of your user interface. Here&amp;#39;s a look at the code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= for err &amp;lt;- upload_errors(@uploads.image, entry) do %&amp;gt;
  &amp;lt;p class=&amp;quot;alert alert-danger&amp;quot;&amp;gt;&amp;lt;%= friendly_error(err) %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we use the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.Helpers.html#upload_errors/2&quot;&gt;&lt;code&gt;Phoenix.LiveView.Helpers.upload_errors/2&lt;/code&gt;&lt;/a&gt; function to return the errors for the specified upload.&lt;/p&gt;
&lt;p&gt;The error messages aren&amp;#39;t very user-friendly, though. So, we&amp;#39;ll implement a helper function, &lt;code&gt;friendly_error/1&lt;/code&gt;, in our LiveView component that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.ProductLive.FormComponent do
  # ...

  def friendly_error(:too_large), do: &amp;quot;Image too large&amp;quot;
  def friendly_error(:too_many_files), do: &amp;quot;Too many files&amp;quot;
  def friendly_error(:not_accepted), do: &amp;quot;Unacceptable file type&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&amp;#39;s more that LiveView file uploads can do. LiveView makes it easy to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cancel an upload&lt;/li&gt;
&lt;li&gt;upload multiple files for a given upload config&lt;/li&gt;
&lt;li&gt;upload files directly from the client to a cloud provider&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and more.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/uploads.html#content&quot;&gt;LiveView file upload documentation&lt;/a&gt; for details.&lt;/p&gt;
&lt;h2&gt;Wrap-up: Build Complex Forms Easily with Phoenix LiveView&lt;/h2&gt;
&lt;p&gt;LiveView enables reactive file uploads right out of the box. Without writing any JavaScript, or even any custom HTML, you can build interactive file upload forms directly into your live view.&lt;/p&gt;
&lt;p&gt;LiveView handles the details of client/server communication and upload state management, leaving you on the hook to write a very small amount of custom code specifying how your uploads should behave and how uploaded files should be saved.&lt;/p&gt;
&lt;p&gt;This is a pattern you&amp;#39;ll see again and again in LiveView — the framework handles the communication and state management details of our SPA, and we can focus on writing application-specific code to support our features.&lt;/p&gt;
&lt;p&gt;Now that you&amp;#39;ve had a glimpse of what LiveView can do with form uploads, you&amp;#39;re ready to build complex, interactive forms that support real-time uploads in the wild. Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Under the Hood of Macros in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/10/05/under-the-hood-of-macros-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/10/05/under-the-hood-of-macros-in-elixir.html</id>
    <published>2021-10-05T00:00:00+00:00</published>
    <updated>2021-10-05T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of our metaprogramming series, find out about the inner workings of macros in Elixir.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This post was updated on 9 August 2023 with the sections &amp;#39;What are Macros in Elixir?&amp;#39; and &amp;#39;Why You Need Macros&amp;#39;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Welcome back to part two of this series on metaprogramming in Elixir. In &lt;a href=&quot;/2021/09/07/an-introduction-to-metaprogramming-in-elixir.html&quot;&gt;part one&lt;/a&gt;, we introduced metaprogramming and gave a brief overview of macros.&lt;/p&gt;
&lt;p&gt;In this part, we will explore the inner workings and behaviors of macros in more depth.&lt;/p&gt;
&lt;p&gt;Although we had discussed what macros are in the previous post, it doesn&amp;#39;t hurt to refresh our memory on what macros are and why they are important.&lt;/p&gt;
&lt;h2&gt;What are Macros in Elixir?&lt;/h2&gt;
&lt;p&gt;Macros are powerful compile-time constructs that generate and modify code before it is compiled into bytecode.
&lt;a href=&quot;https://elixir-lang.org/getting-started/meta/macros.html&quot;&gt;Elixir macros&lt;/a&gt; are used to define new language constructs, extend already existing ones, or perform other code transformations that are necessary for developer productivity.&lt;/p&gt;
&lt;h2&gt;Why You Need Macros&lt;/h2&gt;
&lt;p&gt;In a nutshell, Elixir macros are important because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They can help you handle abstraction. By writing macros to handle all sorts of specialized functionalities in your app, you&amp;#39;ll likely end up with a more
maintable code base as your app grows, since complexity is handled properly.&lt;/li&gt;
&lt;li&gt;You can use them to run compile-time code checks, which will help your overall code quality.&lt;/li&gt;
&lt;li&gt;They are perfect for creating Elixir libraries. If you&amp;#39;ve used a library like &lt;a href=&quot;https://github.com/ninenines/cowboy&quot;&gt;Cowboy&lt;/a&gt; or even Ecto, then what you see is an example of an Elixir macro.
So if your goal is to create an Elixir library to share with the Elixir community or for your own purposes, you will find that macros are the perfect way to go about it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And with that, we can now see what happens during the compilation process of an Elixir app.&lt;/p&gt;
&lt;h2&gt;Stages of Elixir&amp;#39;s Compilation Process&lt;/h2&gt;
&lt;p&gt;We can boil down the Elixir compilation process to the following basic stages:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-10/compilation_process.png&quot; alt=&quot;Compilation process of an Elixir program&quot;/&gt;&lt;/p&gt;
&lt;p&gt;(Note: the actual compilation process of an Elixir program is more intricate than above.)&lt;/p&gt;
&lt;p&gt;The compilation process can be broken down into the following phases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Parsing&lt;/strong&gt; — The Elixir source code (program) is parsed into an AST, which we will call the &lt;strong&gt;initial AST&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expansion&lt;/strong&gt; — The initial AST is scanned and macro calls are identified. Macros are executed. Their output (AST) is injected and expanded into the callsite. Expansion occurs recursively, and a &lt;strong&gt;final AST&lt;/strong&gt; is generated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bytecode generation phase&lt;/strong&gt; — After the final AST is generated, the compiler performs an additional set of
operations that eventually generate and execute BEAM VM
bytecode.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you can see, macros sit at the expansion phase, right before code is converted into bytecode. Therefore,
a good knowledge of the expansion phase helps us understand how macros work.&lt;/p&gt;
&lt;h2&gt;Expansion Phase&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s start by first examining the expansion phase on a general level.&lt;/p&gt;
&lt;p&gt;The compiler will expand macros (as per &lt;code&gt;Macro.expand&lt;/code&gt;) to become part of the program&amp;#39;s pre-generated AST. Macro expansion occurs recursively, meaning that Elixir will continue expanding a macro
until it reaches its most fundamental AST form.&lt;/p&gt;
&lt;p&gt;As macros expand right before bytecode is generated, they can
modify a program&amp;#39;s behavior during compile-time.&lt;/p&gt;
&lt;p&gt;If we dig a little deeper, we will find that the compiler first injects the output AST of a macro at its callsite. Then the AST is expanded recursively.&lt;/p&gt;
&lt;p&gt;We can observe this behavior as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro foo do
    quote do
      IO.inspect(&amp;quot;hello&amp;quot;)
    end
  end
end

iex(1)&amp;gt; require Foo
iex(2)&amp;gt; ast = quote do: Foo.foo
{{:., [], [{:__aliases__, [alias: false], [:Foo]}, :foo]}, [no_parens: true],
 []}
iex(3)&amp;gt; ast |&amp;gt; Macro.expand(__ENV__)
{{:., [],
  [
    {:__aliases__, [counter: -576460752303423391, alias: false], [:IO]},
    :inspect
  ]}, [], [&amp;quot;hello&amp;quot;]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ast&lt;/code&gt; represents the initial AST generated by the compiler before expansion. It holds a reference to the macro
&lt;code&gt;Foo.foo&lt;/code&gt; but it is not expanded as the macro has not been evaluated yet.&lt;/p&gt;
&lt;p&gt;When we call &lt;code&gt;Macro.expand&lt;/code&gt; on the given AST, the compiler begins by injecting the behavior of the macro
into the callsite. We can expand the AST one step at a time using
&lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Macro.html#expand_once/2&quot;&gt;&lt;code&gt;Macro.expand_once&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Contexts in Macros&lt;/h2&gt;
&lt;p&gt;Now that we understand the basics of the expansion phase, we can investigate the parts of a macro.&lt;/p&gt;
&lt;p&gt;Macros contain two contexts — a macro context and a caller context:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro foo do
  # This is the macro&amp;#39;s context, this is executed when the macro is called

  # This is the return value of the macro (AST)
  quote do
    # This is the caller&amp;#39;s context, this is executed when the callsite is called
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the macro&amp;#39;s context is any expression declared before the &lt;code&gt;quote&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The caller&amp;#39;s context is the behavior
declared in the &lt;code&gt;quote&lt;/code&gt;. The &lt;code&gt;quote&lt;/code&gt; generated AST is the macro&amp;#39;s output and is
injected into and expanded at the callsite.&lt;/p&gt;
&lt;p&gt;The behavior defined under the
caller&amp;#39;s context &amp;#39;belongs&amp;#39; to the caller, not the module where the macro is defined. The following example, taken from &lt;a href=&quot;https://pragprog.com/titles/cmelixir/metaprogramming-elixir/&quot;&gt;Metaprogramming
Elixir&lt;/a&gt;, illustrates this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Mod do
  defmacro definfo do
    IO.puts &amp;quot;definfo :: Macro&amp;#39;s context #{__MODULE__}&amp;quot;

    quote do
      IO.puts &amp;quot;definfo :: Caller&amp;#39;s context #{__MODULE__}&amp;quot;

      def friendly_info do
        IO.puts &amp;quot;friend_info :: Module name #{__MODULE__}&amp;quot;
      end
    end
  end
end

defmodule MyModule do
  require Mod
  Mod.definfo
end

iex(1)&amp;gt; c &amp;quot;context.exs&amp;quot;
definfo :: Macro&amp;#39;s context Elixir.Mod
definfo :: Caller&amp;#39;s context Elixir.MyModule
[Mod, MyModule]
iex(2)&amp;gt; MyModule.friendly_info
friend_info :: Module name Elixir.MyModule
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the module that executes the macro&amp;#39;s context is &lt;code&gt;Mod&lt;/code&gt;. But the module that executes the caller&amp;#39;s
context is &lt;code&gt;MyModule&lt;/code&gt; — the callsite where the macro is injected and expanded.&lt;/p&gt;
&lt;p&gt;Similarly,
when we declare &lt;code&gt;friendly_info&lt;/code&gt;, we inject this function into the callsite of the macro, which is &lt;code&gt;MyModule&lt;/code&gt;. So the function now &amp;#39;belongs&amp;#39; to &lt;code&gt;MyModule&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But why does there need to be
two different contexts? What exactly makes the macro context and caller context different from one another?&lt;/p&gt;
&lt;h2&gt;Order of Evaluation in Macro and Caller Contexts&lt;/h2&gt;
&lt;p&gt;The key difference between the macro context and the caller context is that behavior is evaluated at different times.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro foo do
    IO.puts(&amp;quot;macro&amp;quot;)
    quote do
      IO.puts(&amp;quot;caller&amp;quot;)
    end
  end
end

iex(1)&amp;gt; require Foo
iex(2)&amp;gt; ast = quote do: Foo.foo
{{:., [], [{:__aliases__, [alias: false], [:Foo]}, :foo]}, [no_parens: true],
 []}

iex(3)&amp;gt; ast |&amp;gt; Macro.expand(__ENV__)
macro
{{:., [],
  [{:__aliases__, [counter: -576460752303423293, alias: false], [:IO]}, :puts]},
 [], [&amp;quot;caller&amp;quot;]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we expand the AST of a macro call, the macro context is evaluated and the caller context is injected
and expanded into the callsite.&lt;/p&gt;
&lt;p&gt;However, we can go a level deeper.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look again at the first component of the expansion phase: &lt;em&gt;Macros are executed. Their output (AST) is injected and expanded into the callsite&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For a compiler to know what AST needs
to be injected into the callsite, it has to retrieve the output of the macro during
compilation (when the expansion phase occurs). The macro call is parsed as an AST during the parsing phase. The compiler identifies and executes these macro call ASTs prior to the expansion phase.&lt;/p&gt;
&lt;p&gt;If we think of macros as regular functions, the macro context is the function body and the caller context is
the result of the function. During compilation, a macro is executed and evaluates the macro context. Then the &lt;code&gt;quote&lt;/code&gt; is
evaluated, returning the results of the function. The caller context is injected and expanded into the callsite of the
macro.&lt;/p&gt;
&lt;p&gt;The macro context is evaluated during compile-time and treated as a regular function body. It executes within and is &amp;#39;owned&amp;#39; by its containing module.&lt;/p&gt;
&lt;p&gt;The caller context is injected into the callsite, so it is &amp;#39;owned&amp;#39; by the caller. It is evaluated whenever the callsite is evaluated.&lt;/p&gt;
&lt;p&gt;The example above showcases what
happens when a macro is invoked at the module level. But what if we attempt to invoke the macro in a function?
When do the macro and caller contexts evaluate?&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Well, we can use another example here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro foo do
    IO.puts(&amp;quot;macro&amp;quot;)

    quote do
      IO.puts(&amp;quot;caller&amp;quot;)
    end
  end
end

defmodule Bar do
  require Foo

  def execute do
    IO.puts(&amp;quot;execute&amp;quot;)
    Foo.foo
  end
end

macro
iex(1)&amp;gt; Bar.execute
execute
caller
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The caller context evaluates when the function is called (as we established earlier).&lt;/p&gt;
&lt;p&gt;However, something interesting happens with our macro context — it evaluates when the module compiles. This evaluation only happens once when &lt;code&gt;Bar&lt;/code&gt; compiles, as evidenced by the lack of &amp;quot;macro&amp;quot; in our output
when we call &lt;code&gt;Bar.execute&lt;/code&gt;. Why is this the case?&lt;/p&gt;
&lt;p&gt;Well, we only need to evaluate the macro once to retrieve its output (caller context) and inject it into the callsite (which is a function in this case). The caller context behavior evaluates every time the function is called.&lt;/p&gt;
&lt;p&gt;This difference in the order and time of evaluation helps guide us on when to use
the macro and the caller contexts.&lt;/p&gt;
&lt;p&gt;We use the macro context when we want the behavior to be evaluated during compile-time. This is regardless of when the caller context is evaluated or where the macro is called in the code.&lt;/p&gt;
&lt;p&gt;We use the caller context when we want to invoke behavior injected into the callsite at evaluation.&lt;/p&gt;
&lt;p&gt;Now that we have a better grasp of the Elixir compilation process, macros, and the order of evaluation, we can revisit
&lt;code&gt;unquote&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Revisiting &lt;code&gt;unquote&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;In part one of this series, we established that &lt;code&gt;unquote&lt;/code&gt; evaluates a given expression and injects the result (as an
AST) into the AST built from &lt;code&gt;quote&lt;/code&gt;. This is only a piece of the puzzle.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dig deeper to understand the behavior of &lt;code&gt;unquote&lt;/code&gt; during compilation and the necessity of using it.&lt;/p&gt;
&lt;p&gt;While the rest of the &lt;code&gt;quote&lt;/code&gt; body is evaluated at the same time as the callsite, &lt;code&gt;unquote&lt;/code&gt; is evaluated
(immediately) during compile-time — when the macro is evaluated. &lt;code&gt;unquote&lt;/code&gt; aims to evaluate
and inject the result of a given expression. This expression might contain information that is only available during the
macro evaluation, including variables that are initialized during this process. &lt;code&gt;unquote&lt;/code&gt; must be
evaluated during compile-time along with the macro, so that the AST of the result injects into the &lt;code&gt;quote&lt;/code&gt; that
we build.&lt;/p&gt;
&lt;p&gt;But why do we need to &lt;code&gt;unquote&lt;/code&gt; the expression to inject it into the AST? To answer this, let&amp;#39;s compare the expanded AST of a macro using &lt;code&gt;unquote&lt;/code&gt; against one that does not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro foo(x) do
    quote do
      IO.inspect(x)
    end
  end
end

defmodule Bar do
  defmacro bar(y) do
    quote do
      IO.inspect(unquote(y))
    end
  end
end

iex(1)&amp;gt; require Foo
iex(2)&amp;gt; require Bar
iex(3)&amp;gt; ast_foo = quote do: Foo.foo(1 + 2 * 3)
iex(4)&amp;gt; ast_bar = quote do: Bar.bar(1 + 2 * 3)
iex(5)&amp;gt; ast_foo |&amp;gt; Macro.expand(__ENV__)
{{:., [],
  [
    {:__aliases__, [counter: -576460752303423448, alias: false], [:IO]},
    :inspect
  ]}, [], [{:x, [counter: -576460752303423448], Foo}]}

iex(6)&amp;gt; ast_bar |&amp;gt; Macro.expand(__ENV__)
{{:., [],
  [
    {:__aliases__, [counter: -576460752303423384, alias: false], [:IO]},
    :inspect
  ]}, [],
 [
   {:+, [context: Elixir, import: Kernel],
    [1, {:*, [context: Elixir, import: Kernel], [2, 3]}]}
 ]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Observe that the expanded &lt;code&gt;Foo.foo&lt;/code&gt; AST is vastly different from the &lt;code&gt;Bar.bar&lt;/code&gt; AST even though they are
both given the same variable. This is because Elixir is quite literal with variable references. If a variable is
referenced without &lt;code&gt;unquote&lt;/code&gt;, an AST of that variable reference injects into the AST.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;unquote&lt;/code&gt; ensures that the underlying AST of the variable&amp;#39;s value injects into the &lt;code&gt;quote&lt;/code&gt; body.&lt;/p&gt;
&lt;p&gt;Now you may ask: What is the difference in variable scoping between the evaluation of macros and the
execution of the callsite? Why does it matter?&lt;/p&gt;
&lt;p&gt;The scoping of variables in macros can be a confusing subject, so let&amp;#39;s demystify it.&lt;/p&gt;
&lt;h2&gt;Variable Scoping in Macros&lt;/h2&gt;
&lt;p&gt;Now that we understand how macros are evaluated and expanded, we can look at the scoping of variables in
macros, and when to use the options
&lt;code&gt;unquote&lt;/code&gt; and &lt;code&gt;bind_quoted&lt;/code&gt; in &lt;code&gt;quote&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Due to &lt;a href=&quot;https://elixir-lang.readthedocs.io/en/latest/technical/scoping.html#function-clause-scope&quot;&gt;function clause
scoping&lt;/a&gt;, the arguments of a
variable are initialized and &amp;#39;in scope&amp;#39; during the macro evaluation of a function. Similarly, variables declared and assigned
within a function body remain in scope until the function ceases. The same behavior applies to macros.&lt;/p&gt;
&lt;p&gt;When the macro context is evaluated, its arguments and any initialized variables are &amp;#39;in scope.&amp;#39;
This is why &lt;code&gt;unquote&lt;/code&gt; can evaluate variable references declared as arguments of the macro or any variables
initialized in the macro context.&lt;/p&gt;
&lt;p&gt;Any evaluation of variable initialization in the caller context will initialize these variables within the callsite during execution.&lt;/p&gt;
&lt;p&gt;To understand this difference better, let&amp;#39;s look at a few examples:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro foo do
  quote do
    x = 1 + 1
    def bar, do: IO.inspect(unquote(x))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this first example, &lt;code&gt;unquote&lt;/code&gt; will not work. The variable &lt;code&gt;x&lt;/code&gt; has not yet been initialized, but should have been initialized during the execution of the callsite. The immediate evaluation of &lt;code&gt;unquote&lt;/code&gt; runs too early, so we cannot reference our
variable &lt;code&gt;x&lt;/code&gt; when we need to. When &lt;code&gt;unquote&lt;/code&gt; evaluates during compile-time, it attempts to evaluate the variable
reference expression of &lt;code&gt;x&lt;/code&gt; and finds that it is not in scope.&lt;/p&gt;
&lt;p&gt;How can we fix this? By disabling unquoting. This
means disabling the immediate evaluation of &lt;code&gt;unquote&lt;/code&gt;. We only want &lt;code&gt;unquote&lt;/code&gt; to evaluate when our caller context evaluates. This ensures that
&lt;code&gt;unquote&lt;/code&gt; can properly reference a variable in scope (&lt;code&gt;x&lt;/code&gt;) as variable initialization would have occurred
during the evaluation of the callsite.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro foo do
  quote unquote: false do
    x = 1 + 1
    def bar, do: IO.inspect(unquote(x))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example highlights the impact of scoping in macros. If we attempt to access a variable that is available
during the evaluation of the macro context, &lt;code&gt;unquote&lt;/code&gt; as-is is perfect for us.&lt;/p&gt;
&lt;p&gt;However, suppose we try to access a
variable that is only available during the evaluation of the callsite. In that case, we must disable the immediate unquoting behavior
to initialize variables in scope before &lt;code&gt;unquote&lt;/code&gt; attempts to reference them.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s apply this understanding to two other examples.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro foo(opts) do
  quote bind_quoted: [opts: opts] do
    x = Keyword.get(opts, :x)
    def bar, do: IO.inspect(unquote(x))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we have initialized the variable &lt;code&gt;x&lt;/code&gt; from a keyword list. As the keyword list is initialized
during compile-time (along with the evaluation of the macro context), we first have to bind it to the caller context to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate an initialization of the variable during the evaluation of the callsite, and&lt;/li&gt;
&lt;li&gt;Disable unquoting behavior.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We have to bind &lt;code&gt;opts&lt;/code&gt; to the caller context, as the variable is no longer in scope during the evaluation of the
callsite.&lt;/p&gt;
&lt;p&gt;Finally, we have:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro foo(x) do
  quote do
    def bar, do: IO.inspect(unquote(x))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this last example, &lt;code&gt;x&lt;/code&gt; remains a variable in scope during the evaluation of the macro context — i.e. when
the macro is called. The immediate evaluation of &lt;code&gt;unquote&lt;/code&gt; works in our favor. It
renders &lt;code&gt;unquote(x)&lt;/code&gt; valid, as &lt;code&gt;x&lt;/code&gt; is in scope when &lt;code&gt;unquote&lt;/code&gt; is evaluated.&lt;/p&gt;
&lt;h2&gt;Macro Hygiene in Elixir&lt;/h2&gt;
&lt;p&gt;While we are on the topic of scopes in macros, let&amp;#39;s discuss macro hygiene.&lt;/p&gt;
&lt;p&gt;According to &lt;a href=&quot;https://tutorialspoint.dev/language/c/hygienic-macros-introduction&quot;&gt;tutorialspoint.dev&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hygienic macros are macros whose expansion is guaranteed not to cause the accidental capture of identifiers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means that if we inject and expand a macro into the callsite, we need not worry about the macro&amp;#39;s variables
(defined in the caller context) conflicting with the caller&amp;#39;s variables.&lt;/p&gt;
&lt;p&gt;Elixir ensures this by maintaining a distinction between a caller variable and macro variable. You can explore this further
using an example from the &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/macros.html#macro-hygiene&quot;&gt;official tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A macro variable is declared within the body of &lt;code&gt;quote&lt;/code&gt;, while a caller variable is declared
within the callsite of the macro.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro change do
    quote do: a = 13
  end
end

defmodule Bar do
  require Foo

  def go do
    a = 1
    Foo.change
    a
  end
end

Bar.go
# =&amp;gt; 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, &lt;code&gt;a&lt;/code&gt; referenced in &lt;code&gt;change&lt;/code&gt; is not the same variable &lt;code&gt;a&lt;/code&gt; in the scope of &lt;code&gt;go&lt;/code&gt;. Even when we
attempt to change the value of &lt;code&gt;a&lt;/code&gt;, the value of &lt;code&gt;a&lt;/code&gt; in the scope of &lt;code&gt;go&lt;/code&gt; remains untouched.&lt;/p&gt;
&lt;p&gt;However, there may be a time where you have to reference a variable from the caller&amp;#39;s scope in the macro&amp;#39;s scope.
Elixir provides the macro &lt;code&gt;var!&lt;/code&gt; to bridge the gap between these two scopes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro change do
    quote do: var!(a) = 13
  end
end

defmodule Bar do
  require Foo

  def go do
    a = 1
    Foo.change
    a
  end
end

Bar.go
# =&amp;gt; 13
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This distinction ensures no unintended changes to a variable due to changes within a macro (whose source code
we may not have access to).&lt;/p&gt;
&lt;p&gt;You can apply the same hygiene to &lt;a href=&quot;https://hexdocs.pm/elixir/1.6.1/Kernel.html#alias!/1&quot;&gt;aliases and imports&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Understanding &lt;code&gt;require&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;In the code examples shown in this section, we have always used &lt;code&gt;require &amp;lt;module&amp;gt;&lt;/code&gt; before we invoke the macros
within the module. Why is that?&lt;/p&gt;
&lt;p&gt;This is the perfect segue into how the compiler resolves modules containing macros — particularly the order in which
modules are compiled.&lt;/p&gt;
&lt;p&gt;In Elixir, modules compile &lt;a href=&quot;https://elixir-lang.org/blog/2012/04/24/a-peek-inside-elixir-s-parallel-compiler/&quot;&gt;in
parallel&lt;/a&gt;, and usually — for regular
modules — the compiler is smart enough to compile dependencies of functions in the proper order of use. The parallel
compilation process pauses the compilation of a file until the dependency is resolved. This behavior is replicated when handling modules that contain macro invocations.&lt;/p&gt;
&lt;p&gt;However, as macros must be available during compile-time, the module these macros
belong to must be compiled beforehand.
Here&amp;#39;s where &lt;code&gt;require&lt;/code&gt; comes into the picture. &lt;code&gt;require&lt;/code&gt; explicitly informs the compiler to &lt;a href=&quot;https://www.theerlangelist.com/article/macros_2&quot;&gt;compile and load the module
containing the macro first&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We can use an example to illustrate this behavior:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  IO.puts(&amp;quot;Compiling Foo&amp;quot;)

  defmacro foo do
    IO.puts(&amp;quot;Foo.foo := macro&amp;quot;)
    quote do
      IO.puts(&amp;quot;Foo.foo := caller&amp;quot;)
    end
  end
end

defmodule Bar do
  IO.puts(&amp;quot;Compiling Bar&amp;quot;)

  require Foo

  IO.puts(&amp;quot;Bar := before Foo.foo&amp;quot;)
  Foo.foo()
end

Compiling Foo
Foo.foo := macro
Compiling Bar
Bar := before Foo.foo
Foo.foo := caller
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Note that this is just an approximation of the
actual compilation process, but it aims to paint a clearer picture of how &lt;code&gt;require&lt;/code&gt; works.)&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s try to understand why the outputs are in this order.&lt;/p&gt;
&lt;p&gt;Firstly, &lt;code&gt;Bar&lt;/code&gt; tries to compile. The compiler scans and finds a &lt;code&gt;require&lt;/code&gt; for &lt;code&gt;Foo&lt;/code&gt; before evaluating any module-level expressions within the module (such as &lt;code&gt;IO.puts&lt;/code&gt;). So it pauses the compilation of
&lt;code&gt;Bar&lt;/code&gt; and compiles the &lt;code&gt;Foo&lt;/code&gt; module first. As &lt;code&gt;Foo&lt;/code&gt; is compiled, module-level code — like &lt;code&gt;IO.puts&lt;/code&gt; — is
evaluated, and the compiler prints the first line of the output.&lt;/p&gt;
&lt;p&gt;Once &lt;code&gt;Foo&lt;/code&gt; is compiled, the compiler returns to &lt;code&gt;Bar&lt;/code&gt; to resume compilation. &lt;code&gt;Bar&lt;/code&gt; is parsed, macro calls are
executed, and the macro context is evaluated. Even though &lt;code&gt;Foo.foo&lt;/code&gt; is called after
&lt;code&gt;IO.puts(&amp;quot;Bar := before Foo.foo&amp;quot;)&lt;/code&gt;, the evaluation of the macro call takes precedence over the evaluation of
module-level code.&lt;/p&gt;
&lt;p&gt;During expansion, &lt;code&gt;Foo.foo&lt;/code&gt;&amp;#39;s caller context is injected and expanded into the callsite in &lt;code&gt;Bar&lt;/code&gt;. It then behaves just like a regular module-level function call, printing the last three output lines in order of declaration.&lt;/p&gt;
&lt;p&gt;In essence, &lt;code&gt;require&lt;/code&gt; instructs the compiler on the order of compilation that each module should go through if there are
macro dependencies. This ensures that the macros are available during compile-time.&lt;/p&gt;
&lt;h2&gt;Escaping Macros in Elixir&lt;/h2&gt;
&lt;p&gt;Before explaining what &lt;code&gt;Macro.escape&lt;/code&gt; does, let&amp;#39;s look at an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; x = {1, 2, 3}
iex(2)&amp;gt; quote do: unquote(x)
{1, 2, 3}
iex(3)&amp;gt; ast = quote do: IO.inspect(unquote(x))
{{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [], [{1, 2, 3}]}
iex(4)&amp;gt; Code.eval_quoted(ast)
** (CompileError) nofile: invalid quoted expression: {1, 2, 3}

Please make sure your quoted expressions are made of valid AST nodes. If you would like to introduce a value into the
AST, such as a four-element tuple or a map, make sure to call Macro.escape/1 before
    (stdlib 3.15) lists.erl:1358: :lists.mapfoldl/3
    (elixir 1.11.3) lib/code.ex:706: Code.eval_quoted/3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is a strange error. Based on our understanding of &lt;code&gt;unquote&lt;/code&gt; and macros, the code should work as intended,
but it doesn&amp;#39;t. Why is that?&lt;/p&gt;
&lt;p&gt;Well, the answer is found on &lt;code&gt;iex(2)&lt;/code&gt;. When we attempt to unquote &lt;code&gt;x&lt;/code&gt;, we return not an AST, but a tuple — the
same one initially assigned to &lt;code&gt;x&lt;/code&gt;. The error then points to the fact that the tuple is an invalid quoted
expression.&lt;/p&gt;
&lt;p&gt;When we
&lt;code&gt;unquote(x)&lt;/code&gt; as-is, we inject a raw tuple into the AST, which cannot be evaluated as it is not a
valid AST and throws an error.&lt;/p&gt;
&lt;p&gt;So, how do we fix it?&lt;/p&gt;
&lt;p&gt;We need to convert the raw tuple referenced by &lt;code&gt;x&lt;/code&gt; into a valid AST. This can be achieved by
escaping this value using &lt;code&gt;Macro.escape&lt;/code&gt;. Let&amp;#39;s understand what &lt;code&gt;Macro.escape&lt;/code&gt; does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; a = {1, 2, 3}
{1, 2, 3}
iex(2)&amp;gt; Macro.escape(a)
{:{}, [], [1, 2, 3]}
iex(3)&amp;gt; quote do: unquote(a)
{1, 2, 3}
iex(4)&amp;gt; quote do: unquote(Macro.escape(a))
{:{}, [], [1, 2, 3]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;iex(2)&lt;/code&gt;, we see that &lt;code&gt;Macro.escape(a)&lt;/code&gt; returns an AST of the tuple, not the raw tuple — and this is exactly what we
are looking for. By combining &lt;code&gt;Macro.escape&lt;/code&gt;&amp;#39;s behavior with &lt;code&gt;unquote&lt;/code&gt;, we can inject the AST of the tuple into
the &lt;code&gt;quote&lt;/code&gt; as seen in &lt;code&gt;iex(4)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s test this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; x = {1, 2, 3}
{1, 2, 3}
iex(2)&amp;gt; quote do: unquote(Macro.escape(x))
{:{}, [], [1, 2, 3]}
iex(3)&amp;gt; ast = quote do: IO.inspect(unquote(Macro.escape(x)))
{{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [],
 [{:{}, [], [1, 2, 3]}]}
iex(4)&amp;gt; Code.eval_quoted(ast)
{1, 2, 3}
{{1, 2, 3}, []}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the code works just as intended because we escape the tuple.&lt;/p&gt;
&lt;p&gt;Often when working with data structures like tuples and dictionaries, you may find that the injected data from &lt;code&gt;unquote&lt;/code&gt;
does not inject a valid AST. In these cases, you should use &lt;code&gt;Macro.escape&lt;/code&gt; before &lt;code&gt;unquote&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Guard Clauses and Pattern Matching&lt;/h2&gt;
&lt;p&gt;Finally, it&amp;#39;s worth mentioning that, much like regular functions defined through &lt;code&gt;def&lt;/code&gt;, macros can use &lt;a href=&quot;https://inquisitivedeveloper.com/lwm-elixir-24/&quot;&gt;guard
clauses&lt;/a&gt; and &lt;a href=&quot;https://elixirschool.com/en/lessons/basics/pattern-matching/&quot;&gt;pattern
matching&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro foo(x) when x == 4 do
  IO.inspect(&amp;quot;macro with x being 4&amp;quot;)
end

defmacro foo(_) do
  IO.inspect(&amp;quot;macro with any other value&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Up Next: Applications of Macros in Elixir&lt;/h2&gt;
&lt;p&gt;Congratulations, you&amp;#39;ve made it to the end of this part! You should now have a better grasp of how macros work internally.&lt;/p&gt;
&lt;p&gt;In part three, we will look at the many applications of macros in Elixir.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Real-Time Form Validation with Phoenix LiveView</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/09/28/real-time-form-validations-with-phoenix-liveview.html"/>
    <id>https://blog.appsignal.com/2021/09/28/real-time-form-validations-with-phoenix-liveview.html</id>
    <published>2021-09-28T00:00:00+00:00</published>
    <updated>2021-09-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how you can build LiveView forms that validate changes and provide real-time feedback to users.</summary>
    <content type="html">&lt;p&gt;LiveView is a compelling choice for building modern web apps. Built on top of Elixir&amp;#39;s OTP tooling and leveraging WebSockets, it offers super-fast real-time, interactive features alongside impressive developer productivity.&lt;/p&gt;
&lt;p&gt;LiveView keeps the developer&amp;#39;s mind firmly rooted on the server-side, even when testing and debugging. This can empower you to deliver interactive features in single-page apps faster than ever before. Some of the most common interactions on the web are form validation and submission. These days, users expect to see form feedback presented to them in real-time, and LiveView offers first-class support for exactly that.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;#39;ll show you how to build LiveView forms that validate changes and provide feedback to the user in real-time. Along the way, you&amp;#39;ll learn how to model change in your Phoenix application with schemaless changesets and compose LiveView code to handle that change.&lt;/p&gt;
&lt;h2&gt;The Feature: Adding a Form to a Phoenix LiveView App&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;The form examples we&amp;#39;ll be looking at in this post are inspired by the &amp;quot;Forms and Changesets&amp;quot; chapter in my book, &lt;a href=&quot;https://pragprog.com/titles/liveview/programming-phoenix-liveview/&quot;&gt;Programming LiveView&lt;/a&gt;, co-authored with Bruce Tate. Check it out for an even deeper dive into LiveView testing and so much more.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Before we dive into writing any actual code, let&amp;#39;s talk about the feature we&amp;#39;ll build. Imagine that you&amp;#39;re responsible for a Phoenix web app, Arcade, that provides in-browser games to users. A user can log in, select a game to play, and even invite friends to play games with them.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll focus on that last piece of functionality. A user can invite a friend to play a game with them by filling out a form with the friend&amp;#39;s email address. This will email a link to the recipient&amp;#39;s email address so they can join the game.&lt;/p&gt;
&lt;p&gt;Our form will need to implement some validation — namely, to ensure that a valid email address is provided. It should show any validation errors, as well as the results of a successful form submission in real-time. We won&amp;#39;t worry too much about the exact details of sending emails for now. Instead, we&amp;#39;ll keep our focus on the form validations in LiveView.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll begin where you&amp;#39;ll almost always want to start when building a new feature in a Phoenix application — in the application core. We&amp;#39;ll model game invitations in their module. You&amp;#39;ll build a boundary layer in a Phoenix context module that we&amp;#39;ll call on in LiveView later to validate form input and send invitation emails.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Model Change in Phoenix with Ecto Changesets&lt;/h2&gt;
&lt;p&gt;We&amp;#39;re almost ready to start writing code. But first, let&amp;#39;s think about the role that forms and changesets play in our Phoenix application.&lt;/p&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html&quot;&gt;Ecto changesets&lt;/a&gt;. Changesets are policies for changing data, and they:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Cast unstructured user data&lt;/em&gt; into a known, structured form — most commonly, an Ecto database schema, ensuring data &lt;em&gt;safety&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Capture differences&lt;/em&gt; between safe, consistent data and a proposed change, allowing for &lt;em&gt;efficiency&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Validate data&lt;/em&gt; using known consistent rules, ensuring data &lt;em&gt;consistency&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Provide a &lt;em&gt;contract&lt;/em&gt; for communicating error states and valid states, ensuring a &lt;em&gt;common interface for change&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def changeset(game, attrs) do
  game
  |&amp;gt; cast(attrs, [:name, :description, :unit_price, :sku])
  |&amp;gt; validate_required([:name, :description, :unit_price, :sku])
  |&amp;gt; unique_constraint(:sku)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;changeset/2&lt;/code&gt; function captures differences between the structured &lt;code&gt;game&lt;/code&gt; and the unstructured &lt;code&gt;attrs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, with &lt;code&gt;cast/4&lt;/code&gt;, the changeset trims the attributes to a known field list and converts them to the correct types. This ensures safety by guaranteeing that you won&amp;#39;t let any unknown or invalid attributes into your database.&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;validate/2&lt;/code&gt; and &lt;code&gt;unique_constraint/2&lt;/code&gt; functions validate the inbound data, ensuring consistency.&lt;/p&gt;
&lt;p&gt;The result is a data structure with known states and error message formats, ensuring interface compatibility.&lt;/p&gt;
&lt;p&gt;Consequently, any forms that use this changeset know exactly how to behave — validating form input and presenting errors in accordance with the changeset&amp;#39;s rules.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;re going to shift off of this well-known path of generated changesets. You&amp;#39;ll see just how versatile changesets can be when it comes to modeling changes to data, with or without a database. You&amp;#39;ll build a custom, schemaless changeset for data that &lt;em&gt;isn&amp;#39;t&lt;/em&gt; backed by a database table, and you&amp;#39;ll use that changeset in a form within a live view.&lt;/p&gt;
&lt;h2&gt;Schemaless Changesets in the Phoenix Application Core&lt;/h2&gt;
&lt;p&gt;You&amp;#39;ve likely used changesets to model changes to data that is persisted in your database. Our game invitation feature doesn&amp;#39;t require database persistence, however. A user will provide the email address of the friend they&amp;#39;d like to invite, and our application will simply send out the email with the link to the game. We don&amp;#39;t need to store that invitee&amp;#39;s data at this point.&lt;/p&gt;
&lt;p&gt;Luckily, we can use schemaless changesets to model data that &lt;em&gt;doesn&amp;#39;t&lt;/em&gt; get saved to the database. A schemaless changeset is based on a simple Elixir map or struct, rather than an Ecto schema-backed struct. The only difference is that, when working with a plain Elixir struct, we need to provide the changeset with the type of information that Elixir would normally handle. We&amp;#39;ll see this in action in a moment.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s define the core module that we&amp;#39;ll use to model a game Recipient. Create a new file, &lt;code&gt;arcade/lib/game/Recipient.ex&lt;/code&gt;, and define the module like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Arcade.Invite.Recipient do
  defstruct [:name, :email]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our module is simple so far. It implements a struct with two keys, &lt;code&gt;:name&lt;/code&gt; and &lt;code&gt;:email&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Next up, we need to give our module awareness of the types that will be considered valid by any changeset we create. Let&amp;#39;s use a module attribute to store this map of types so that we can access it later:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Arcade.Invite.Recipient do
  defstruct [:name, :email]
  @types %{game_name: :string, email: :string}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we&amp;#39;ll alias the module and import &lt;code&gt;Ecto.Changeset&lt;/code&gt; so that we can use the changeset functions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Arcade.Invite.Recipient do
  defstruct [:name, :email]
  @types %{game_name: :string, email: :string}

  alias Arcade.Invite.Recipient
  import Ecto.Changeset
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we&amp;#39;re ready to define the &lt;code&gt;changeset/2&lt;/code&gt; function that will be responsible for casting recipient data into a changeset and validating it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Arcade.Invite.Recipient do
  # ...
  def changeset(%Recipient{} = invitation, attrs) do
    {invitation, @types}
    |&amp;gt; cast(attrs, Map.keys(@types))
    |&amp;gt; validate_required([:game_name, :email])
    |&amp;gt; validate_format(:email, ~r/@/)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We validate the presence of the &lt;code&gt;:game_name&lt;/code&gt; and &lt;code&gt;:email&lt;/code&gt; attributes, and then validate the format of &lt;code&gt;:email&lt;/code&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Now, we can create recipient changesets like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; alias Arcade.Invite.Recipient
iex&amp;gt; i = %Recipient
iex&amp;gt; Recipient.changeset(r, %{email: &amp;quot;juniper@email.com&amp;quot;, game_name: &amp;quot;Chess&amp;quot;})
#Ecto.Changeset&amp;lt;...valid?: true&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s see what happens if we try to create a changeset with an attribute of an invalid type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Recipient.changeset(r, %{email: &amp;quot;juniper@email.com&amp;quot;, game_name: 1234})
#Ecto.Changeset&amp;lt;errors: [game_name: {&amp;quot;is invalid&amp;quot;, ...]}],valid?: false&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Ecto.Changeset.cast/4&lt;/code&gt; relies on &lt;code&gt;@types&lt;/code&gt; to identify the invalid type and provide a descriptive error.&lt;/p&gt;
&lt;p&gt;Next, try a changeset that breaks one of the custom validation rules:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Recipient.changeset(r, %{email: &amp;quot;juniper&amp;#39;s email&amp;quot;, game_name: &amp;quot;Chess&amp;quot;})
#Ecto.Changeset&amp;lt;changes: %{email: &amp;quot;juniper&amp;#39;s email&amp;quot;, ...},
  errors: [email: {&amp;quot;has invalid format&amp;quot;, ...}],valid?: false&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function successfully captures our change policy in code, and the returned changeset tells the user exactly what is wrong.&lt;/p&gt;
&lt;p&gt;Now that our changeset is up and running, let&amp;#39;s quickly build out an &lt;code&gt;Invite&lt;/code&gt; context that will present the interface for interacting with the changeset.&lt;/p&gt;
&lt;h2&gt;The Boundary Layer in Elixir&lt;/h2&gt;
&lt;p&gt;Create a file, &lt;code&gt;lib/arcade/invite.ex&lt;/code&gt; and add in the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Arcade.Invite do
  alias Arcade.Invite.Recipient

  def change_invitation(%Recipient{} = recipient, attrs \\ %{}) do
    Recipient.changeset(recipient, attrs)
  end

  def send_invite(recipient, attrs) do
    # send email to promo recipient
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This context is a beautifully concise boundary for our service. The &lt;code&gt;change_invitation/2&lt;/code&gt; function returns a recipient changeset, and &lt;code&gt;send_invite/2&lt;/code&gt; is a placeholder for sending a game invite email.&lt;/p&gt;
&lt;p&gt;Other than the internal tweaks we made inside &lt;code&gt;Recipient.changeset/2&lt;/code&gt;, building a Phoenix context module with a schemaless changeset looks identical to building an Ecto-backed one. When all is said and done, in the view layer, schemaless changesets and schema-backed ones will look identical.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s turn our attention to the view layer now and build out our live view.&lt;/p&gt;
&lt;h2&gt;Build and Define the Live View&lt;/h2&gt;
&lt;p&gt;This live view will have the feel of a typical live view with a form. First, we&amp;#39;ll create a simple route and wire it to a live view. Next, we&amp;#39;ll use our &lt;code&gt;Invite&lt;/code&gt; context to produce a schemaless changeset, and add it to the socket within a &lt;code&gt;mount/3&lt;/code&gt; function. We&amp;#39;ll render a form with this changeset and apply changes to the changeset by handling events from the form.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;p&gt;Create a file, &lt;code&gt;lib/arcade_web/live/invite_live.ex&lt;/code&gt; and fill in the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ArcadeWeb.InviteLive do
  use ArcadeWeb, :live_view
  alias Arcade.Invite
  alias Arcade.Invite.Recipient

  def mount(_params, _session, socket) do
    {:ok, socket}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We pull in the LiveView behavior, alias our modules for later use and implement a simple &lt;code&gt;mount/3&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s use an implicit &lt;code&gt;render/1&lt;/code&gt;. Create a template file in &lt;code&gt;lib/arcade_web/live/invite_live.html.leex&lt;/code&gt;, starting with some simple markup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h2&amp;gt;Invite a Friend to Play!&amp;lt;/h2&amp;gt;
&amp;lt;h4&amp;gt;
  Enter the name of a game and your friend&amp;#39;s email below and we&amp;#39;ll send them an
  invite to join you in playing a game!
&amp;lt;/h4&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&amp;#39;s define a live route and fire up the server. In the router, add the following route behind authentication:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;scope &amp;quot;/&amp;quot;, ArcadeWeb do
  pipe_through [:browser, :require_authenticated_user]
  live &amp;quot;/invite&amp;quot;, InviteLive
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, you should be able to fire up the Phoenix server, point your browser at &lt;code&gt;/invite&lt;/code&gt; and see your live view render the invitation template:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-09/form-validations-simple-text.png&quot; alt=&quot;invite page intro text&quot;/&gt;&lt;/p&gt;
&lt;p&gt;As the live view is up and running, we&amp;#39;re ready to build out the form for an invitation recipient.&lt;/p&gt;
&lt;h3&gt;Render the Phoenix LiveView Form&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll use &lt;code&gt;mount/3&lt;/code&gt; to store a recipient struct and a changeset in the socket:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt; def mount(_params, _session, socket) do
  {:ok,
    socket
    |&amp;gt; assign_recipient()
    |&amp;gt; assign_changeset()}
end

def assign_recipient(socket) do
  socket
  |&amp;gt; assign(:recipient, %Recipient{})
end

def assign_changeset(%{assigns: %{recipient: recipient}} = socket) do
  socket
  |&amp;gt; assign(:changeset, Invite.change_invitation(recipient))
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;mount/3&lt;/code&gt; function uses two helper functions, &lt;code&gt;assign_recipient/1&lt;/code&gt; and &lt;code&gt;assign_changeset/1&lt;/code&gt;, to add a recipient struct and a changeset for that recipient to socket assigns. These pure, single-purpose reducer functions are reusable building blocks for managing the live view&amp;#39;s state.&lt;/p&gt;
&lt;p&gt;Remarkably, the schemaless changeset can be used in our form exactly like database-backed ones. We&amp;#39;ll use &lt;code&gt;socket.assigns.changeset&lt;/code&gt; in the template&amp;#39;s form, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= f = form_for @changeset, &amp;quot;#&amp;quot;,
  id: &amp;quot;invite-form&amp;quot;,
  phx_change: &amp;quot;validate&amp;quot;,
  phx_submit: &amp;quot;save&amp;quot; %&amp;gt;

  &amp;lt;%= label f, :game_name %&amp;gt;
  &amp;lt;%= text_input f, :game_name  %&amp;gt;
  &amp;lt;%= error_tag f, :game_name %&amp;gt;

  &amp;lt;%= label f, :email %&amp;gt;
  &amp;lt;%= text_input f, :email%&amp;gt;
  &amp;lt;%= error_tag f, :email %&amp;gt;

  &amp;lt;%= submit &amp;quot;Send Invite&amp;quot;%&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if you point your browser at &lt;code&gt;/invite&lt;/code&gt;, you should see this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-09/form-validations-forms.png&quot; alt=&quot;invite form&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Our form implements two LiveView bindings, &lt;code&gt;phx-change&lt;/code&gt;, and &lt;code&gt;phx-submit&lt;/code&gt;. Let&amp;#39;s dig into these events now.&lt;/p&gt;
&lt;h3&gt;Handle Form Events in LiveView&lt;/h3&gt;
&lt;p&gt;We&amp;#39;ll start with a look at the &lt;code&gt;phx-change&lt;/code&gt; event. LiveView will send a &lt;code&gt;&amp;quot;validate&amp;quot;&lt;/code&gt; event each time the form changes and include the form params in the event metadata.&lt;/p&gt;
&lt;p&gt;So, we&amp;#39;ll implement a &lt;code&gt;handle_event/3&lt;/code&gt; function for this event that builds a new changeset from the params and adds it to the socket:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/arcade_web/live/invite_live.ex
def handle_event(
      &amp;quot;validate&amp;quot;,
      %{&amp;quot;recipient&amp;quot; =&amp;gt; recipient_params},
      %{assigns: %{recipient: recipient}} = socket) do
  changeset =
    recipient
    |&amp;gt; Invite.change_invitation(recipient_params)
    |&amp;gt; Map.put(:action, :validate)

    {:noreply,
    socket
    |&amp;gt; assign(:changeset, changeset)}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s break this down. The &lt;code&gt;Invite.change_invitation/2&lt;/code&gt; context function creates a new changeset using the recipient from socket state and the params from the form change event.&lt;/p&gt;
&lt;p&gt;Then, we use &lt;code&gt;Map.put(:action, :validate)&lt;/code&gt; to add the &lt;code&gt;validate&lt;/code&gt; action to the changeset, a signal that instructs Phoenix to display errors. Phoenix will &lt;em&gt;not&lt;/em&gt; display the changeset&amp;#39;s errors otherwise.&lt;/p&gt;
&lt;p&gt;When you think about it, this approach makes sense. Not all invalid changesets should show errors on the page. For example, the empty form for the new changeset &lt;em&gt;shouldn&amp;#39;t&lt;/em&gt; show any errors because the user hasn&amp;#39;t provided any input yet. So, the Phoenix &lt;code&gt;form_for&lt;/code&gt; function needs to be told when to display a changeset&amp;#39;s errors. If the changeset&amp;#39;s action is empty, then no errors are set on the form object — even if the changeset is invalid and has a non-empty &lt;code&gt;:errors&lt;/code&gt; value.&lt;/p&gt;
&lt;p&gt;Finally, &lt;code&gt;assigns/2&lt;/code&gt; adds the new changeset to the socket, triggering &lt;code&gt;render/1&lt;/code&gt; and displaying any errors.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take a look at the form tag that displays those errors on the page. Typically, each field has a label, an input control, and an error tag, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= label f, :email %&amp;gt;
&amp;lt;%= text_input f, :email%&amp;gt;
&amp;lt;%= error_tag f, :email %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;error_tag/2&lt;/code&gt; Phoenix view helper function displays the form&amp;#39;s errors for a given field on a changeset, when the changeset&amp;#39;s action is &lt;code&gt;:validate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now, point your browser at &lt;code&gt;/invite&lt;/code&gt; and fill out the form with a game name and an invalid email. As you can see in this image, the UI updates to display the validation errors:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-09/form-validations-errors.png&quot; alt=&quot;form with validation errors&quot;/&gt;&lt;/p&gt;
&lt;p&gt;That was surprisingly easy! We built a simple and powerful live view with a reactive form that displays any errors in real-time.&lt;/p&gt;
&lt;p&gt;The live view calls on the context to create a changeset, renders it in a form, validates it on form change, and then re-renders the template after each form event. We get reactive form validation for free without writing any JavaScript or HTML. We let Ecto changesets handle the data validation rules, and we let the LiveView framework handle the client/server communication for triggering validation events and displaying the results.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s just one thing about our form validation that needs some improvement. You&amp;#39;ll notice that as soon as you start typing into the email form, an error appears because our validation event fires whenever the form field changes. This doesn&amp;#39;t present our users with the best experience — we&amp;#39;re telling them there is an error with their input before they get a chance to finish typing their full email.&lt;/p&gt;
&lt;p&gt;Instead, we want the validation event to fire when a user clicks away or blurs from the email input. Luckily for us, LiveView makes it easy to implement this functionality with the help of the &lt;code&gt;phx-debounce&lt;/code&gt; binding. Update your email form field to look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;%= text_input f, :email, phx_debounce: &amp;quot;blur&amp;quot; %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the &lt;code&gt;&amp;quot;validate&amp;quot;&lt;/code&gt; event will only fire when a user blurs away from the email input field, and we won&amp;#39;t show any premature validation error messages.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/bindings.html#rate-limiting-events-with-debounce-and-throttle&quot;&gt;Learn more about LiveView&amp;#39;s support for debouncing and other rate-limiting options&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As you might imagine, the &lt;code&gt;phx-submit&lt;/code&gt; event works very similarly to &lt;code&gt;phx-change&lt;/code&gt;. The &lt;code&gt;&amp;quot;save&amp;quot;&lt;/code&gt; event fires when the user submits the form. To respond to this event, we can implement a &lt;code&gt;handle_event/3&lt;/code&gt; function that uses the (currently empty) context function, &lt;code&gt;Invite.send_invite/2&lt;/code&gt;. The context function should create and validate a changeset.&lt;/p&gt;
&lt;p&gt;If the changeset is, in fact, valid, we can pipe it to some helper function or service that handles the details of sending invitation emails.&lt;/p&gt;
&lt;p&gt;If the changeset is not valid, we can return an error tuple. Then we can update the UI with a success or failure message accordingly. I&amp;#39;ll leave you to practice what you&amp;#39;re learning by implementing this behavior on your own.&lt;/p&gt;
&lt;h2&gt;Wrap-up: LiveView — A Great Choice to Build and Validate Forms in Elixir&lt;/h2&gt;
&lt;p&gt;Now you&amp;#39;ve seen that Ecto changesets are not tightly coupled to the database. Schemaless changesets let you tie backend services to Phoenix forms any time you require validation and security, whether or not your application needs to access a full relational database.&lt;/p&gt;
&lt;p&gt;LiveView supports custom integration of forms to backend code with these schemaless changesets. To do so, you need only provide the &lt;code&gt;Changeset.cast/4&lt;/code&gt; function with the first argument of a two-tuple holding both data &lt;em&gt;and&lt;/em&gt; type information. This type of code is ideal for implementing form scenarios requiring validation but without the typical database backend.&lt;/p&gt;
&lt;p&gt;Whether you&amp;#39;re working with schema-backed or schemaless changesets, LiveView provides real-time form validation and feedback, with very little hand-rolled code. We can use LiveView event bindings to handle form validation and submission in real-time with a few simple event handlers that call out to our nice, clean Phoenix context code.&lt;/p&gt;
&lt;p&gt;With that, you have everything you need to build basic forms in LiveView. To dig deeper into LiveView&amp;#39;s rich forms offerings, &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/form-bindings.html#content&quot;&gt;check out the docs&lt;/a&gt;. Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Application Code Upgrades in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/09/14/application-code-upgrades-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/09/14/application-code-upgrades-in-elixir.html</id>
    <published>2021-09-14T00:00:00+00:00</published>
    <updated>2021-09-14T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s examine application code upgrades in the last part of this series.</summary>
    <content type="html">&lt;p&gt;In this third and final part of this series, we will look at what happens during an application upgrade.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Set-up: Create an Appup File in Elixir&lt;/h2&gt;
&lt;p&gt;As with a &lt;a href=&quot;/2021/08/23/using-supervisors-to-organize-your-elixir-application.html&quot;&gt;single module&lt;/a&gt;, we need new compiled code for a fresh version of an application.&lt;/p&gt;
&lt;p&gt;But an application can consist of many modules and have running processes.
So we need a scenario to specify what to upgrade and how to do it.&lt;/p&gt;
&lt;p&gt;These scenarios are called &lt;a href=&quot;http://erlang.org/doc/man/appup.html&quot;&gt;application upgrade files (.appup files)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s try to make an appup file for our application. Imagine that we want to upgrade
our counters so that we can specify counter increment speed.&lt;/p&gt;
&lt;h2&gt;Prepare a New Version of the Application in Elixir&lt;/h2&gt;
&lt;p&gt;First, we&amp;#39;ll add our application to git and tag the old version:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git add .
git commit -m &amp;#39;initial commit&amp;#39;
git tag &amp;#39;v0.1.0&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we should make a new version.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;mix.exs&lt;/code&gt;, update the version to &lt;code&gt;0.1.1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...
 def project do
    [
      app: :our_new_app,
      version: &amp;quot;0.1.1&amp;quot;,
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want &lt;code&gt;interval&lt;/code&gt; to be an external parameter, not a module attribute. Make the following changes in &lt;code&gt;lib/our_new_app/counter.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule OurNewApp.Counter do
  ...
  def start_link({start_from, interval}) do
    GenServer.start_link(__MODULE__, {start_from, interval})
  end

  ...

  def init({start_from, interval}) do
    Process.flag(:trap_exit, true)

    st = %{
      current: start_from,
      timer: :erlang.start_timer(interval, self(), :tick),
      terminator: nil,
      interval: interval
    }

    {:ok, st}
  end

  ...

  def handle_info({:timeout, _timer_ref, :tick}, st) do
    :erlang.cancel_timer(st.timer)

    new_current = st.current + 1

    if st.terminator &amp;amp;&amp;amp; rem(new_current, 10) == 0 do
      # we are terminating
      GenServer.reply(st.terminator, :ok)
      {:stop, :normal, %{st | current: new_current, timer: nil}}
    else
      new_timer = :erlang.start_timer(st.interval, self(), :tick)
      {:noreply, %{st | current: new_current, timer: new_timer}}
    end
  end

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now add a &lt;code&gt;code_change&lt;/code&gt; callback to the same file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule OurNewApp.Counter do
  ...

  def code_change(_old_vsn, st, new_interval) do
    {:ok, Map.put(st, :interval, new_interval)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;And change supervisor specs in &lt;code&gt;lib/our_new_app/counter_sup.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  @impl true
  def init(start_numbers) do
    children =
      for start_number &amp;lt;- start_numbers do
        # We can&amp;#39;t just use `{OurNewApp.Counter, start_number}`
        # because we need different id&amp;#39;s for children

        Supervisor.child_spec({OurNewApp.Counter, {start_number, 200}}, id: start_number)
      end

    Supervisor.init(children, strategy: :one_for_one)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s construct &lt;code&gt;our_new_app.appup&lt;/code&gt; file.
We need to update our supervision specs and pass a new tick interval (250) to &lt;code&gt;change_code&lt;/code&gt; callback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;{
    &amp;quot;0.1.1&amp;quot;,
    [{&amp;quot;0.1.0&amp;quot;, [
        {update, &amp;#39;Elixir.OurNewApp.CounterSup&amp;#39;, supervisor},
        {update, &amp;#39;Elixir.OurNewApp.Counter&amp;#39;, {advanced, 250}}
    ]}],
    [{&amp;quot;0.1.0&amp;quot;, []}]
}.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this file is written in &lt;strong&gt;Erlang&lt;/strong&gt; syntax.&lt;/p&gt;
&lt;p&gt;Now tag your new version:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git add .
git commit -m &amp;#39;added customizable intervals&amp;#39;
git tag &amp;#39;v0.1.1&amp;#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try to upgrade &lt;code&gt;0.1.0&lt;/code&gt; to &lt;code&gt;0.1.1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Checkout, compile, and run &lt;code&gt;0.1.0&lt;/code&gt; version:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;git checkout v0.1.0
iex -S mix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a &lt;strong&gt;separate shell and different directory&lt;/strong&gt;, checkout the new version and put the appup file in the appropriate place:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;...
git checkout v0.1.0
mix compile
cp our_new_app.appup _build/dev/lib/our_new_app/ebin
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Run the Application Upgrade in Elixir&lt;/h2&gt;
&lt;p&gt;We are ready to upgrade the application. In the running iex session, do the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Application.spec(:our_new_app)
[
  description: &amp;#39;our_new_app&amp;#39;,
  id: [],
  vsn: &amp;#39;0.1.0&amp;#39;,
  modules: [OurNewApp, OurNewApp.Application, OurNewApp.Counter,
   OurNewApp.CounterSup],
  maxP: :infinity,
  maxT: :infinity,
  registered: [],
  included_applications: [],
  applications: [:kernel, :stdlib, :elixir, :logger],
  mod: {OurNewApp.Application, []},
  start_phases: :undefined
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that the old application is running.&lt;/p&gt;
&lt;p&gt;Run an &amp;quot;orphaned&amp;quot; counter outside the supervision tree (we will need it later):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(2)&amp;gt; {:ok, pid} = OurNewApp.Counter.start_link(30000)
{:ok, #PID&amp;lt;0.147.0&amp;gt;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check that your appup file is correct and the OTP knows how to upgrade your application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(3)&amp;gt; :release_handler.upgrade_script(:our_new_app, &amp;#39;/path/to/new/version/of/our_new_app/_build/dev/lib/our_new_app/&amp;#39;)
{:ok, &amp;#39;0.1.1&amp;#39;,
 [
   {:load_object_code,
    {:our_new_app, &amp;#39;0.1.1&amp;#39;, [OurNewApp.CounterSup, OurNewApp.Counter]}},
   :point_of_no_return,
   {:suspend, [OurNewApp.CounterSup]},
   {:load, {OurNewApp.CounterSup, :brutal_purge, :brutal_purge}},
   {:code_change, :up, [{OurNewApp.CounterSup, []}]},
   {:resume, [OurNewApp.CounterSup]},
   {:suspend, [OurNewApp.Counter]},
   {:load, {OurNewApp.Counter, :brutal_purge, :brutal_purge}},
   {:code_change, :up, [{OurNewApp.Counter, 250}]},
   {:resume, [OurNewApp.Counter]}
 ]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check your counter processes and their pids:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(4)&amp;gt; Supervisor.which_children(OurNewApp.CounterSup)
[
  {20000, #PID&amp;lt;0.143.0&amp;gt;, :worker, [OurNewApp.Counter]},
  {10000, #PID&amp;lt;0.142.0&amp;gt;, :worker, [OurNewApp.Counter]}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upgrade the application!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(5)&amp;gt; :release_handler.upgrade_app(:our_new_app, &amp;#39;/path/to/new/version/of/our_new_app/_build/dev/lib/our_new_app/&amp;#39;)
{:ok, []}
iex(6)&amp;gt;
02:46:48.286 [info]  terminating with {{:badkey, :interval, %{current: 33478, terminator: nil, timer: #Reference&amp;lt;0.948322908.3672375303.146224&amp;gt;}}, [{OurNewApp.Counter, :handle_info, 2, [file: &amp;#39;lib/our_new_app/counter.ex&amp;#39;, line: 52]}, {:gen_server, :try_dispatch, 4, [file: &amp;#39;gen_server.erl&amp;#39;, line: 680]}, {:gen_server, :handle_msg, 6, [file: &amp;#39;gen_server.erl&amp;#39;, line: 756]}, {:proc_lib, :init_p_do_apply, 3, [file: &amp;#39;proc_lib.erl&amp;#39;, line: 226]}]}, counter is 33478

02:46:48.291 [error] GenServer #PID&amp;lt;0.147.0&amp;gt; terminating
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s see what happened:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; Application.spec(:our_new_app)
[
  description: &amp;#39;our_new_app&amp;#39;,
  id: [],
  vsn: &amp;#39;0.1.1&amp;#39;,
  modules: [OurNewApp, OurNewApp.Application, OurNewApp.Counter,
   OurNewApp.CounterSup],
  maxP: :infinity,
  maxT: :infinity,
  registered: [],
  included_applications: [],
  applications: [:kernel, :stdlib, :elixir, :logger],
  mod: {OurNewApp.Application, []},
  start_phases: :undefined
]
iex(2)&amp;gt; Supervisor.which_children(OurNewApp.CounterSup)
[
  {20000, #PID&amp;lt;0.143.0&amp;gt;, :worker, [OurNewApp.Counter]},
  {10000, #PID&amp;lt;0.142.0&amp;gt;, :worker, [OurNewApp.Counter]}
]
iex(3)&amp;gt; pids = for {_, pid, _, _} &amp;lt;- Supervisor.which_children(OurNewApp.CounterSup), do: pid
[#PID&amp;lt;0.143.0&amp;gt;, #PID&amp;lt;0.142.0&amp;gt;]
iex(4)&amp;gt; OurNewApp.Counter.get(Enum.at(pids, 0))
27225
iex(5)&amp;gt; OurNewApp.Counter.get(Enum.at(pids, 1))
17235
iex(6)&amp;gt; :sys.get_state(Enum.at(pids, 0))
%{
  current: 27468,
  interval: 250,
  terminator: nil,
  timer: #Reference&amp;lt;0.948322908.3672375311.146315&amp;gt;
}
iex(7)&amp;gt; :sys.get_state(Enum.at(pids, 1))
%{
  current: 17476,
  interval: 250,
  terminator: nil,
  timer: #Reference&amp;lt;0.948322908.3672375311.146330&amp;gt;
}
iex(8)&amp;gt; :sys.get_state(OurNewApp.CounterSup)
{:state, {:local, OurNewApp.CounterSup}, :one_for_one,
 {[20000, 10000],
  %{
    10000 =&amp;gt; {:child, #PID&amp;lt;0.142.0&amp;gt;, 10000,
     {OurNewApp.Counter, :start_link, [{10000, 200}]}, :permanent, 5000,
     :worker, [OurNewApp.Counter]},
    20000 =&amp;gt; {:child, #PID&amp;lt;0.143.0&amp;gt;, 20000,
     {OurNewApp.Counter, :start_link, [{20000, 200}]}, :permanent, 5000,
     :worker, [OurNewApp.Counter]}
  }}, :undefined, 3, 5, [], 0, OurNewApp.CounterSup, [10000, 20000]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our upgrade process was successfully completed.&lt;/p&gt;
&lt;p&gt;You can see that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The new version of the application is now running.&lt;/li&gt;
&lt;li&gt;Our child counters are alive — they updated their state and are functioning.&lt;/li&gt;
&lt;li&gt;From the internal state of &lt;code&gt;OurNewApp.CounterSup&lt;/code&gt;, we see those child specifications for our counters updated too! Now, if they die, they will properly restart.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But what about the error &lt;code&gt;GenServer #PID&amp;lt;0.147.0&amp;gt; terminating&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Recall that
&lt;code&gt;#PID&amp;lt;0.147.0&amp;gt;&lt;/code&gt; is the pid of our &amp;quot;orphaned&amp;quot; counter, which was running outside of the supervision tree. As the application upgrade process traverses the supervision tree and updates processes,
the &amp;quot;orphaned&amp;quot; counter&amp;#39;s state was not updated. But the code of the &lt;code&gt;OurNewApp.Counter&lt;/code&gt;
did update, so the &amp;quot;orphaned&amp;quot; counter process died: new code met its old state.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ve seen how to upgrade a single running application.
We needed only two special tools for that: an &lt;code&gt;.appup&lt;/code&gt; file and &lt;code&gt;:release_handler.upgrade_app/2&lt;/code&gt; function.
It was also crucial for us to follow OTP principles.&lt;/p&gt;
&lt;h2&gt;Wrap-up and What to Learn Next&lt;/h2&gt;
&lt;p&gt;I hope you&amp;#39;ve enjoyed this whirlwind ride through production code upgrades in Elixir! We started with my guide to hot code reloading, followed by the best use of supervisors when building applications.&lt;/p&gt;
&lt;p&gt;This final article has demonstrated how following OTP principles can show us the way to powerful application code upgrades.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s worth noting that the application code upgrade I&amp;#39;ve demonstrated here still has disadvantages. The critical issue is that if the whole OS beam process restarts, this will load our application&amp;#39;s old code (unless we take some action).&lt;/p&gt;
&lt;p&gt;How can we handle this potential problem, I hear you ask? With so-called &lt;em&gt;release upgrades&lt;/em&gt;. &lt;a href=&quot;https://learnyousomeerlang.com/relups&quot;&gt;This awesome article from &amp;#39;Learn you some Erlang&amp;#39;&lt;/a&gt; is a good starting point to dive into release upgrades.&lt;/p&gt;
&lt;p&gt;Thanks again for taking the time to read this series — and happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Metaprogramming in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/09/07/an-introduction-to-metaprogramming-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/09/07/an-introduction-to-metaprogramming-in-elixir.html</id>
    <published>2021-09-07T00:00:00+00:00</published>
    <updated>2021-09-07T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first of this four-part series, learn some fundamentals of metaprogramming as well as some Elixir metaprogramming secrets.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This post was updated on 9 August 2023. The &amp;#39;Types of Metaprogramming&amp;#39; and &amp;#39;Why Do Metaprogramming?&amp;#39; sections were switched, so that &amp;#39;Why Do Metaprogramming?&amp;#39; is now covered before &amp;#39;Types of Metaprogramming&amp;#39;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this world, there are many mysteries — but few are as elusive as metaprogramming in Elixir.&lt;/p&gt;
&lt;p&gt;In this four-part series, we&amp;#39;ll start by looking at core concepts and then explore how metaprogramming operates in Elixir specifically.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s develop an understanding of metaprogramming and uncover some Elixir metaprogramming secrets!&lt;/p&gt;
&lt;h2&gt;Introducing Metaprogramming in Elixir&lt;/h2&gt;
&lt;p&gt;According to Harald Sondergaard, metaprogramming is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;a programming technique in which computer programs have the ability to treat other programs as their data; meaning that
a program can be designed to read, generate, analyze, or transform other programs, and even modify itself while
running.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In essence, metaprogramming — much like metadata — revolves around &amp;quot;a set of programs that describe and give information about other programs&amp;quot; (adapted from the &lt;a href=&quot;https://www.lexico.com/definition/metadata&quot;&gt;Oxford dictionary definition of metadata&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Before we get into how to do metaprogramming in Elixir, let&amp;#39;s understand why we are doing it in the first place.&lt;/p&gt;
&lt;h2&gt;Why Do Metaprogramming?&lt;/h2&gt;
&lt;p&gt;We will look at how to use metaprogramming specifically in Elixir. But first, let&amp;#39;s cover some general concepts and benefits of metaprogramming to understand why
we do it in the first place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adapt code to runtime factors&lt;/strong&gt; - One of the benefits of metaprogramming is generating code that can adapt to different run-time factors. This is great
if you need your software to be dynamic and respond to varying factors at runtime.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance optimization&lt;/strong&gt; - It&amp;#39;s possible to use metaprogramming to customize your code in such a way that it leads to better performance compared to trying to
achieve the same with a static codebase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reduce errors&lt;/strong&gt; - Using metaprogramming technniques, you can reduce errors that are bound to occur when you copy-paste code a lot. By using macros that generate code
on the fly, it&amp;#39;s possible to reduce the need for manual copy-paste operations that would likely introduce errors and other code mistakes at compile-time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DSLs&lt;/strong&gt; - With metaprogramming, a developer can easily create a domain-specific language to better express how to handle a particular scenario in their project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is just a small snapshot of the possibilities available to a developer through using metaprogramming (we&amp;#39;ll also highlight a few uses later in the article).
That said, one thing you&amp;#39;ll observe here is the frequent use of the terms &amp;quot;run-time&amp;quot; and &amp;quot;compile-time&amp;quot;. Let&amp;#39;s see what they mean next.&lt;/p&gt;
&lt;h2&gt;Defining Run-time and Compile-time&lt;/h2&gt;
&lt;p&gt;We can broadly classify metaprogramming into two categories: compile-time and run-time metaprogramming.&lt;/p&gt;
&lt;p&gt;But what exactly are run-time and compile-time? They both refer to stages of a program&amp;#39;s life cycle.&lt;/p&gt;
&lt;p&gt;Compile-time is the stage at which source code converts to binary code or intermediate binary code for a machine or virtual machine to execute. Run-time refers to when code executes.&lt;/p&gt;
&lt;p&gt;The program life cycle includes the following steps:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-09/program-lifecycle.png&quot; alt=&quot;Typical program lifecycle&quot;/&gt;
&lt;em&gt;Source: &lt;a href=&quot;https://en.wikipedia.org/wiki/Program_lifecycle_phase&quot;&gt;https://en.wikipedia.org/wiki/Program_lifecycle_phase&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Note that this is not a complete representation of the entire program life cycle, just a simplified one.&lt;/p&gt;
&lt;p&gt;Compilation &amp;quot;sets the program in stone&amp;quot; by converting it into binary code. Metaprogramming exposes this process
to allow developers to &amp;quot;move computation from run-time to compile-time&amp;quot; or &amp;quot;generate code using compile-time
computations&amp;quot;. This essentially allows the modification of the source code before/during compile-time, meaning that the
generated binary code is slightly different.&lt;/p&gt;
&lt;p&gt;Self-modifying code is rather unique. In essence, it performs reflection during run-time. The life cycle of a self-modifying program looks a little different:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-09/self-modifying-program-lifecycle.png&quot; alt=&quot;Program lifecycle of a self-modifying program&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You can substitute the &amp;quot;binary&amp;quot; for any intermediate language generated by the compiler, such as JVM bytecode or, in Elixir&amp;#39;s case, BEAM VM bytecode.&lt;/p&gt;
&lt;h2&gt;Types of Metaprogramming&lt;/h2&gt;
&lt;p&gt;There are two types of metaprogramming that prescribe varying degrees of control over a given program:&lt;/p&gt;
&lt;h3&gt;Introspection&lt;/h3&gt;
&lt;p&gt;Introspection refers to a program revealing metadata about other programs or itself.&lt;/p&gt;
&lt;p&gt;This definition broadly covers the first part of the definition of metaprogramming: &amp;quot;a program can be designed to read...[and] analyze...other programs&amp;quot;. The program has access to information about itself or other programs.&lt;/p&gt;
&lt;h3&gt;Reflection&lt;/h3&gt;
&lt;p&gt;Reflection refers to a program modifying other programs or itself.&lt;/p&gt;
&lt;p&gt;If a program can modify other programs or itself, it — by definition — has access to the metadata of the program, revealing information like names of functions.&lt;/p&gt;
&lt;p&gt;By looking at the two types of metaprogramming, we can conclude that reflection encompasses introspection, or introspection is a subset of reflection:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-09/metaprogramming-types.png&quot; alt=&quot;Types of metaprogramming&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Interesting Uses of Metaprogramming&lt;/h2&gt;
&lt;p&gt;The general definition of metaprogramming also encompasses the tools used in a program&amp;#39;s life cycle.&lt;/p&gt;
&lt;p&gt;For instance, a language compiler is a metaprogramming application designed to receive another program as input and generate binary as output.&lt;/p&gt;
&lt;p&gt;We can narrow down broad metaprogramming use cases to the following, more specific, applications in a programming language context:&lt;/p&gt;
&lt;h3&gt;Code generation&lt;/h3&gt;
&lt;p&gt;By generating code dynamically during compile-time, it&amp;#39;s available during run-time. When the nature of the code that&amp;#39;s generated is not fixed, this can prove especially useful. For instance, you can use code generation to design domain-specific languages (DSLs) or generate functions based on input such as files or APIs.&lt;/p&gt;
&lt;h3&gt;Code instrumentation&lt;/h3&gt;
&lt;p&gt;Code instrumentation refers to the measure of a program&amp;#39;s
performance, error diagnosis, and logging of trace information.&lt;/p&gt;
&lt;p&gt;Metaprogramming enables this through dynamic program analysis — software analysis performed by running software through a real or virtual processor.&lt;/p&gt;
&lt;p&gt;Code instrumentation enables features like code coverage, memory error detection, fault localization, and concurrency errors.&lt;/p&gt;
&lt;h3&gt;Behavioral changes&lt;/h3&gt;
&lt;p&gt;This refers to changing the behavior of a program through metaprogramming. Behavioral changes can include &lt;a href=&quot;https://martinfowler.com/articles/feature-toggles.html&quot;&gt;feature toggling&lt;/a&gt;, where a given feature is toggled on/off through a flag that is read during compile-time/run-time.&lt;/p&gt;
&lt;p&gt;This article series is about metaprogramming within Elixir, so our key focus will be on code generation.&lt;/p&gt;
&lt;h2&gt;Metaprogramming in Elixir: The Basics&lt;/h2&gt;
&lt;p&gt;Elixir applies a style of metaprogramming known as macro system metaprogramming (also used in other languages like Rust and Lisp).&lt;/p&gt;
&lt;p&gt;In Elixir, metaprogramming allows developers to leverage existing features to build new features that suit
their individual business requirements.&lt;/p&gt;
&lt;p&gt;The foundation of metaprogramming in Elixir is macros.&lt;/p&gt;
&lt;h2&gt;Defining Macros&lt;/h2&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://elixir-lang.org/getting-started/meta/macros.html&quot;&gt;official macros documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Macros are compile-time constructs that are invoked with Elixir&amp;#39;s AST as input and a superset of Elixir&amp;#39;s AST as
output.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are two critical components to this definition. Let&amp;#39;s break them down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Compile-time constructs&lt;/strong&gt; - evaluated and available during compile-time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elixir&amp;#39;s AST&lt;/strong&gt; - Abstract Syntax Trees (ASTs) are tree
representations of the abstract syntax structure of the source code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We use the representations of the source code as building blocks for compile-time constructs. Since the compiler reasons with the source code through ASTs, we effectively &amp;quot;speak&amp;quot; the compiler&amp;#39;s language to build constructs that it can directly reason with.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;In Elixir, ASTs are &lt;a href=&quot;https://hexdocs.pm/elixir/1.12.3/Tuple.html&quot;&gt;tuples&lt;/a&gt;, so we reason with the compiler in a manner that is familiar to us. We do not need to deviate from Elixir&amp;#39;s syntax to begin writing macros, which lowers our barrier to entry of learning macros. On top of that, we do not even need to write ASTs ourselves. There are constructs in Elixir to handle all of that heavy lifting for us.&lt;/p&gt;
&lt;p&gt;The above definition also mentions how a macro receives an AST as input and returns a superset of AST as output. So, you can think of a macro as a regular function with inputs, behavior, and an output. The overall goal is to use a given AST to generate a new AST for the compiler to use.&lt;/p&gt;
&lt;p&gt;There is more to come on the compilation process of Elixir programs in part two of this series.&lt;/p&gt;
&lt;h2&gt;Starting Small with Macros&lt;/h2&gt;
&lt;p&gt;Now that we understand macros, let&amp;#39;s dip our toes into the water and implement a basic macro.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll start with a very basic comparison of a macro to a regular function.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Macro.html&quot;&gt;Elixir documentation&lt;/a&gt; inspires this code example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro macro_inspect(value) do
    IO.inspect(value)
    value
  end

  def func_inspect(value) do
    IO.inspect(value)
    value
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To define a macro, we use &lt;code&gt;defmacro&lt;/code&gt; and declare the parameters just as we would a regular function.&lt;/p&gt;
&lt;p&gt;Running the macro in &lt;a href=&quot;https://hexdocs.pm/iex/IEx.html&quot;&gt;IEX&lt;/a&gt; yields the following results:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; import Foo
iex(2)&amp;gt; macro_inspect(1 + 2)
{:+, [context: Elixir, import: Kernel], [1, 2]}
3
iex(3)&amp;gt; func_inspect(1 + 2)
3
3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Observe that rather than printing the result of &lt;code&gt;1 + 2&lt;/code&gt;, the macro prints a tuple instead (the AST as input that we defined earlier).&lt;/p&gt;
&lt;p&gt;When a macro is first declared, the arguments of that macro are automatically converted into AST so that you don&amp;#39;t need to parse the arguments manually. The arguments will not be evaluated beforehand.&lt;/p&gt;
&lt;p&gt;However, when the value of the macro is returned, it yields the result of &lt;code&gt;1 + 2&lt;/code&gt;. The macro should return an AST as output (and it is). However, this AST as output is compiled and executed once the macro is called. The expression &lt;code&gt;1 + 2&lt;/code&gt; is evaluated first, then returned.&lt;/p&gt;
&lt;p&gt;Once we understand the basic syntax and declaration of a macro, we can explore the structure of the AST.&lt;/p&gt;
&lt;h2&gt;AST Structure&lt;/h2&gt;
&lt;p&gt;As mentioned earlier, the AST is the representation of the source code as a syntax tree. In the example above, we inspect the AST of the expression &lt;code&gt;1 + 2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can break down the AST structure into three components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Atom — representing the name of the operation&lt;/li&gt;
&lt;li&gt;Metadata of the expression&lt;/li&gt;
&lt;li&gt;Arguments of the operation&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{
  :+,                                 # operation name,
  [context: Elixir, import: Kernel],  # metadata,
  [1, 2]                              # operation arguments
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While you must understand what comprises an AST, we rarely need to read/write raw ASTs.&lt;/p&gt;
&lt;p&gt;Elixir makes it ridiculously easy to interface with macros, so we hardly even need to think about the structure of the AST that we are working on — everything is handled for us.&lt;/p&gt;
&lt;h2&gt;Interacting with ASTs&lt;/h2&gt;
&lt;p&gt;As mentioned earlier, ASTs represent the source code and are the input and output of macros. They are the cornerstone of macros. We need to interact with the AST representations of expressions freely, without getting bogged down by reading and writing the ASTs ourselves.&lt;/p&gt;
&lt;p&gt;This is where &lt;code&gt;quote&lt;/code&gt; and &lt;code&gt;unquote&lt;/code&gt; come into the picture.&lt;/p&gt;
&lt;p&gt;To generate the AST representation of an expression or body, we use &lt;code&gt;quote&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;quote do
  1 + 2 * 3
end

{:+, [context: Elixir, import: Kernel],
 [1, {:*, [context: Elixir, import: Kernel], [2, 3]}]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we use &lt;code&gt;quote&lt;/code&gt;, we build an AST. While the example above is relatively simple, we will soon discover that &lt;code&gt;quote&lt;/code&gt; can be used to build much more complex ASTs.&lt;/p&gt;
&lt;p&gt;What if we have a value we want to use in our &lt;code&gt;quote&lt;/code&gt;, such as the arguments? We attempt to introduce an external (outside of &lt;code&gt;quote&lt;/code&gt;) variable into &lt;code&gt;quote&lt;/code&gt;, by using &lt;code&gt;unquote&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;unquote&lt;/code&gt; evaluates its argument, which is an expression, and injects the result (as an AST) into the AST being built. As
&lt;a href=&quot;https://elixir-lang.org/crash-course.html/&quot;&gt;everything in Elixir is an expression&lt;/a&gt;, we evaluate expressions to inject the results.&lt;/p&gt;
&lt;p&gt;For instance, if &lt;code&gt;unquote&lt;/code&gt; receives a variable, we will evaluate that expression as the underlying expression referenced by the variable and inject that.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;unquote&lt;/code&gt; receives a full expression like
&lt;code&gt;1 + 2 * 3&lt;/code&gt;, we will evaluate that to &lt;code&gt;7&lt;/code&gt; and inject that. &lt;code&gt;unquote&lt;/code&gt; expects that the result of the expression is a valid AST.&lt;/p&gt;
&lt;p&gt;In part two of this series, we&amp;#39;ll discuss the consequences of having an invalid AST and delve into macros more deeply.&lt;/p&gt;
&lt;p&gt;Do you recall that macros automatically convert arguments into their AST forms? We will leverage that behavior:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro foo(exp) do
    quote do
      doubled = unquote(exp) * 2
      doubled
    end
  end
end

Foo.foo(1 + 2 * 3)
14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we have built a macro called &lt;code&gt;foo&lt;/code&gt; which receives an expression as an argument. Then, we begin to build an AST for the macro in &lt;code&gt;quote&lt;/code&gt;. We use &lt;code&gt;unquote(exp)&lt;/code&gt; to inject the value of the &lt;code&gt;exp&lt;/code&gt; argument into the AST.&lt;/p&gt;
&lt;p&gt;You might ask yourself: How do I know that the expression is injected and not evaluated right away?&lt;/p&gt;
&lt;p&gt;Well, we can use a handy tool to inspect the AST of the macro and understand how it works under the hood:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; require Foo
iex(2)&amp;gt; ast = quote do: Foo.foo(1 + 2 * 3)
iex(3)&amp;gt; ast |&amp;gt; Macro.expand(__ENV__)
{:__block__, [],
 [
   {:=, [],
    [
      {:doubled, [counter: -576460752303423358], Foo},
      {:*, [context: Foo, import: Kernel],
       [
         {:+, [context: Elixir, import: Kernel],
          [1, {:*, [context: Elixir, import: Kernel], [2, 3]}]},
         2
       ]}
    ]},
   {:doubled, [counter: -576460752303423358], Foo}
 ]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we generate the AST of the macro call and assign it to a variable.&lt;/p&gt;
&lt;p&gt;Then, with our &lt;code&gt;ast&lt;/code&gt; variable, we will use
&lt;code&gt;Macro.expand&lt;/code&gt; to expand the AST to its fullest form.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll look at macro expansion next time. For now, think of it as peeling back the layers of an AST to its most fundamental components.&lt;/p&gt;
&lt;p&gt;As you can see, the expanded form of the &lt;code&gt;Foo.foo&lt;/code&gt; call contains the AST of &lt;code&gt;1 + 2 * 3&lt;/code&gt;. This proves that &lt;code&gt;unquote&lt;/code&gt; only injected the AST of the expression into the &lt;code&gt;quote&lt;/code&gt; AST, but didn&amp;#39;t evaluate it. The evaluation is performed later on (we will get into this in part two as well).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;Macro.expand&lt;/code&gt; will only attempt to perform expansion on the root node of the AST.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Macro.html#expand/2&quot;&gt;You can find more information about &lt;code&gt;Macro.expand&lt;/code&gt;
in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;quote&lt;/code&gt; Options in Elixir&lt;/h2&gt;
&lt;p&gt;Now that we understand the fundamentals of macros, we can start to look at our &lt;code&gt;quote&lt;/code&gt; options.&lt;/p&gt;
&lt;p&gt;While &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/Kernel.SpecialForms.html#quote/2-options&quot;&gt;there are several options with &lt;code&gt;quote&lt;/code&gt;&lt;/a&gt;, we will focus on the three most frequently used and introduce the concepts behind each option.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;unquote&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Toggles the unquoting behavior in &lt;code&gt;quote&lt;/code&gt;. By disabling it, any &lt;code&gt;unquote&lt;/code&gt; call is converted to an AST of the macro call (as with any other macro/function call).&lt;/p&gt;
&lt;p&gt;This defers the evaluation of &lt;code&gt;unquote&lt;/code&gt; to a later point. I&amp;#39;ll explain why you&amp;#39;d want to do so in the next part of this series.&lt;/p&gt;
&lt;p&gt;For now, let&amp;#39;s look at the following example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; a = [foo: 1, bar: 1]
iex(2)&amp;gt; ast = quote do: unquote(a)
  [foo: 1, bar: 1]
iex(3)&amp;gt; ast = quote unquote: false, do: unquote(a)
  {:unquote, [], [{:a, [], Elixir}]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we leave the unquoting behavior enabled (&lt;code&gt;iex(2)&lt;/code&gt;), &lt;code&gt;unquote(a)&lt;/code&gt; will evaluate &lt;code&gt;a&lt;/code&gt; as an expression. This returns the keyword list, which is then injected into the &lt;code&gt;quote&lt;/code&gt; AST — and the result is as expected.&lt;/p&gt;
&lt;p&gt;However, when we disable the unquoting behavior (&lt;code&gt;iex(3)&lt;/code&gt;), &lt;code&gt;unquote(a)&lt;/code&gt; is converted into another AST expression, which is injected into the &lt;code&gt;quote&lt;/code&gt; AST as-is.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;bind_quoted&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Disables unquoting behavior in the &lt;code&gt;quote&lt;/code&gt; and binds given variables in the body of &lt;code&gt;quote&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Binding moves the variable initialization into the body of &lt;code&gt;quote&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can observe this behavior using &lt;code&gt;Macro.to_string&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; a = [foo: 1, bar: 2]
iex(2)&amp;gt; ast = quote bind_quoted: [a: a], do: IO.inspect(a)
iex(3)&amp;gt; ast |&amp;gt; Macro.to_string |&amp;gt; IO.puts
(
  a = [foo: 1, bar: 2]
  IO.inspect(a)
  :ok
)
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, &lt;code&gt;bind_quoted&lt;/code&gt; adds a &amp;quot;copy&amp;quot; of &lt;code&gt;a&lt;/code&gt; into the body of &lt;code&gt;quote&lt;/code&gt; by assigning it in the body of &lt;code&gt;quote&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In a macro, this is equivalent to binding the variable to the caller context, as the variable is initialized during the evaluation of the callsite.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Contexts will be discussed in greater detail next time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  defmodule Foo do
    defmacro foo(x) do
      quote bind_quoted: [x: x] do
        IO.inspect(x)
        end
    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;location&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This option controls whether run-time errors from a macro are reported from the caller or inside the quote.&lt;/p&gt;
&lt;p&gt;By setting this option to &lt;code&gt;:keep&lt;/code&gt;, error messages report specific lines in the macro that cause the error, rather than the line of the callsite.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.SpecialForms.html#quote/2-stacktrace-information&quot;&gt;You can see a code example in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Build a Simple Macro in Elixir&lt;/h2&gt;
&lt;p&gt;We should now be able to build a simple macro that mimics the behavior of an &lt;code&gt;if&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;Recall that an &lt;code&gt;if&lt;/code&gt; statement is comprised of the following components:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;if (condition) do
  # body
else
  # body
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can replicate this structure using our own macro:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule NewIf do
  defmacro if?(condition, do: block, else: other) do
    quote do
      cond do
        unquote(condition) == true -&amp;gt; unquote(block)
        unquote(condition) == false -&amp;gt; unquote(other)
      end
    end
  end
end

iex(1)&amp;gt; require NewIf
iex(2)&amp;gt; NewIf.if? 4 == 5, do: :yes, else: :no
:no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This macro can receive three arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;condition&lt;/code&gt; - predicate to evaluate &lt;code&gt;if?&lt;/code&gt; statement against&lt;/li&gt;
&lt;li&gt;&lt;code&gt;do&lt;/code&gt; - block to execute when &lt;code&gt;condition&lt;/code&gt; is true&lt;/li&gt;
&lt;li&gt;&lt;code&gt;else&lt;/code&gt; - block to execute when &lt;code&gt;condition&lt;/code&gt; is false&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Elixir, such blocks can be declared as arguments if they follow the following syntax: &lt;code&gt;&amp;lt;formal name&amp;gt;: &amp;lt;variable name&amp;gt;&lt;/code&gt;. The formal name is the name used when you call the macro. The variable name is the name used in the macro when you&amp;#39;re attempting to reference the block.&lt;/p&gt;
&lt;p&gt;After receiving these three arguments, we start by building an AST using &lt;code&gt;quote&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Using a &lt;code&gt;cond&lt;/code&gt; statement, we determine which body &lt;code&gt;if?&lt;/code&gt; should execute. We use &lt;code&gt;unquote&lt;/code&gt; to inject the values of &lt;code&gt;condition&lt;/code&gt;, &lt;code&gt;block&lt;/code&gt;, and &lt;code&gt;other&lt;/code&gt; into the AST we are building.&lt;/p&gt;
&lt;p&gt;In doing so, when the macro is evaluated, the condition is evaluated to be &lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt;, and, based on that result, we will either execute &lt;code&gt;block&lt;/code&gt; or &lt;code&gt;other&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We wrap up this behavior into an AST returned by &lt;code&gt;quote&lt;/code&gt; (which is the return value of the macro).&lt;/p&gt;
&lt;h2&gt;Next Up: Macros in Detail&lt;/h2&gt;
&lt;p&gt;Now we have a good grasp on the foundations of metaprogramming in general and specifically in Elixir.&lt;/p&gt;
&lt;p&gt;Join me for the next part of this series, where we&amp;#39;ll look into the intricacies behind macros and how everything works.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>LiveView Integration Tests in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/08/31/liveview-integration-tests-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/08/31/liveview-integration-tests-in-elixir.html</id>
    <published>2021-08-31T00:00:00+00:00</published>
    <updated>2021-08-31T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second part of this two-part series, you&#039;ll write interactive LiveView tests that validate a full set of live view behaviors.</summary>
    <content type="html">&lt;p&gt;In the second part of this two-part series, we&amp;#39;ll write an integration test that validates interactions within a single live view, and an integration test that validates the interactions between two separate live views.&lt;/p&gt;
&lt;p&gt;You will focus on testing the behavior of the survey results chart filter from the previous post. We&amp;#39;ll use the &lt;code&gt;LiveViewTest&lt;/code&gt; module&amp;#39;s functions to simulate LiveView connections without a browser. With the help of this module, your tests can mount and render live views, trigger events, and then execute assertions against the rendered view.&lt;/p&gt;
&lt;p&gt;That&amp;#39;s the whole LiveView lifecycle.&lt;/p&gt;
&lt;p&gt;So let&amp;#39;s get going and write some interactive LiveView tests!&lt;/p&gt;
&lt;h2&gt;Testing Interactions within a Live View&lt;/h2&gt;
&lt;p&gt;Our first integration test focuses on the interactions within a single live view. We&amp;#39;ll validate the live view&amp;#39;s behavior when a user performs some activity on the page. First off, we&amp;#39;re going to take a look at the feature that we&amp;#39;ll be testing.&lt;/p&gt;
&lt;h2&gt;The Feature&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;SurveyResultsLive&lt;/code&gt; component mentioned in the previous post is rendered within a parent live view, &lt;code&gt;AdminDashboardLive&lt;/code&gt;, that lives at the &lt;code&gt;/admin-dashboard&lt;/code&gt; route. Here&amp;#39;s a refresher of the content displayed by that component:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-08/survey-results-age-group-filtered.png&quot; alt=&quot;survey results chart&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Here, you see a chart that displays survey results and can be filtered by a given age group.&lt;/p&gt;
&lt;p&gt;Our test will simulate a user&amp;#39;s visit to &lt;code&gt;/admin-dashboard&lt;/code&gt;, followed by their filter selection of the &lt;code&gt;18 and under&lt;/code&gt; age group. The test will verify an updated survey results chart that displays product ratings from users in that age group.&lt;/p&gt;
&lt;p&gt;Because components run in their parent&amp;#39;s processes, we&amp;#39;ll focus our tests on the &lt;code&gt;AdminDashboardLive&lt;/code&gt; view. &lt;code&gt;LiveViewTest&lt;/code&gt; helper functions will run our admin dashboard live view and interact with the survey results chart. Along the way, you&amp;#39;ll get a taste for the wide variety of interactions that the &lt;code&gt;LiveViewTest&lt;/code&gt; module allows you to test.&lt;/p&gt;
&lt;p&gt;Begin by setting up a LiveView test for the &lt;code&gt;AdminDashboardLive&lt;/code&gt; view.&lt;/p&gt;
&lt;h2&gt;The Test&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s best to segregate unit tests and integration tests into their own modules, so create a new file &lt;code&gt;test/gamestore_web/live/admin_dashboard_live_test.exs&lt;/code&gt; and define the module with some fixtures, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GamestoreWeb.AdminDashboardLiveTest do
  use GamestoreWeb.ConnCase

  import Phoenix.LiveViewTest
  alias Gamestore.{Accounts, Survey, Catalog}

  @create_product_attrs %{description: &amp;quot;test description&amp;quot;, name: &amp;quot;Test Game&amp;quot;, sku: 42, unit_price: 120.5}
  @create_user_attrs %{email: &amp;quot;test@test.com&amp;quot;, password: &amp;quot;passwordpassword&amp;quot;}
  @create_user2_attrs %{email: &amp;quot;test2@test.com&amp;quot;, password: &amp;quot;passwordpassword&amp;quot;}
  @create_user3_attrs %{email: &amp;quot;test3@test.com&amp;quot;, password: &amp;quot;passwordpassword&amp;quot;}
  @create_demographic_attrs %{gender: &amp;quot;female&amp;quot;, year_of_birth: DateTime.utc_now.year - 15}
  @create_demographic_over_18_attrs %{gender: &amp;quot;female&amp;quot;, year_of_birth: DateTime.utc_now.year - 30}

  defp product_fixture do
    {:ok, product} = Catalog.create_product(@create_product_attrs)
    product
  end

  defp user_fixture(attrs \\ @create_user_attrs) do
    {:ok, user} = Accounts.register_user(attrs)
    user
  end

  defp demographic_fixture(user, attrs) do
    attrs =
      attrs
      |&amp;gt; Map.merge(%{user_id: user.id})
    {:ok, demographic} = Survey.create_demographic(attrs)
    demographic
  end

  defp rating_fixture(user, product, stars) do
    {:ok, rating} = Survey.create_rating(%{stars: stars, user_id: user.id, product_id: product.id})
    rating
  end

  defp create_product(_) do
    product = product_fixture()
    %{product: product}
  end

  defp create_user(_) do
    user = user_fixture()
    %{user: user}
  end

  defp create_demographic(user, attrs \\ @create_demographic_attrs) do
    demographic = demographic_fixture(user, attrs)
    %{demographic: demographic}
  end

  defp create_rating(user, product, stars) do
    rating = rating_fixture(user, product, stars)
    %{rating: rating}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s break this down. First, our test module uses the &lt;code&gt;GamestoreWeb.ConnCase&lt;/code&gt; behavior. This lets us route to live views using the test connection by giving our tests access to a context map with a key of &lt;code&gt;:conn&lt;/code&gt; pointing to a value of the test connection. Then, import the &lt;code&gt;LiveViewTest&lt;/code&gt; module to get access to LiveView testing functions.&lt;/p&gt;
&lt;p&gt;Lastly, define some fixtures that you&amp;#39;ll use to create test data. The nitty-gritty details of those fixture functions aren&amp;#39;t important. Just understand that they generate the database records needed to log in users and render the admin dashboard page to display a chart with product ratings.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Now that our module is set up, we&amp;#39;ll add a &lt;code&gt;describe&lt;/code&gt; block to encapsulate the feature we&amp;#39;re testing—the survey results chart functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;describe &amp;quot;Survey Results&amp;quot; do
  setup [:register_and_log_in_user, :create_product, :create_user]

  setup %{user: user, product: product} do
    create_demographic(user)
    create_rating(user, product, 2)

    user2 = user_fixture(@create_user2_attrs)
    create_demographic(user2, @create_demographic_over_18_attrs)
    create_rating(user2, product, 3)
    :ok
  end
  # test coming soon!
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two calls to &lt;code&gt;setup/1&lt;/code&gt; seed the test database with a product, users, demographics, and ratings. One of the two users is in the &lt;code&gt;18 and under&lt;/code&gt; age group, and the other is in a different age group. Then we create a rating for each user.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re also using a test helper provided for us by the &lt;a href=&quot;https://github.com/aaronrenner/phx_gen_auth&quot;&gt;Phoenix authentication generator&lt;/a&gt;—&lt;code&gt;register_and_log_in_user/1&lt;/code&gt;. This function creates a &lt;code&gt;conn&lt;/code&gt; struct with a logged-in user, a necessary step because visiting the &lt;code&gt;/admin-dashboard&lt;/code&gt; route requires an authenticated user.&lt;/p&gt;
&lt;p&gt;Now that our setup is complete, define the test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;describe &amp;quot;Survey Results&amp;quot; do
  # ...
  test &amp;quot;it filters by age group&amp;quot;, %{conn: conn} do
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before writing the body of our test, make a plan. To test this feature, we need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mount and render the live view.&lt;/li&gt;
&lt;li&gt;Find the age group drop-down menu and select an item from it.&lt;/li&gt;
&lt;li&gt;Assert that the re-rendered survey results chart has the correct data and markup.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is the pattern you&amp;#39;ll always apply to testing live view features: run the live view, simulate some interaction, then validate the rendered result. This pattern should sound familiar—it neatly matches up to the three-step testing process we&amp;#39;ve been using so far:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up preconditions&lt;/li&gt;
&lt;li&gt;Provide input&lt;/li&gt;
&lt;li&gt;Validate your expectations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Begin with the first step: mounting and rendering the LiveView. Call the &lt;code&gt;LiveViewTest.live/2&lt;/code&gt; function, which takes in the test &lt;code&gt;conn&lt;/code&gt; and spawns a simulated live view process:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it filters by age group&amp;quot;, %{conn: conn} do
  {:ok, view, _html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The call to &lt;code&gt;live/2&lt;/code&gt; returns a three-element tuple with &lt;code&gt;:ok&lt;/code&gt;, the LiveView process, and the rendered HTML returned from the live view&amp;#39;s call to &lt;code&gt;render/1&lt;/code&gt;. We don&amp;#39;t need to access that HTML in this test, so ignore it.&lt;/p&gt;
&lt;p&gt;Components run in their parent&amp;#39;s process. That means the test &lt;em&gt;must&lt;/em&gt; start up the &lt;code&gt;AdminDashboardLive&lt;/code&gt; view rather than rendering &lt;em&gt;just&lt;/em&gt; the &lt;code&gt;SurveyResultsLive&lt;/code&gt; component. By spawning the &lt;code&gt;AdminDashboardLive&lt;/code&gt; view, we&amp;#39;re &lt;em&gt;also&lt;/em&gt; rendering the components of the view.&lt;/p&gt;
&lt;p&gt;So, by interacting with the &lt;code&gt;view&lt;/code&gt; variable representing the &lt;code&gt;AdminDashboardLive&lt;/code&gt; process above, we&amp;#39;ll interact with elements within the &lt;code&gt;SurveyResultsLive&lt;/code&gt; component and test that it behaves appropriately in response to events. This is the correct way to test LiveView component behavior within a live view page.&lt;/p&gt;
&lt;p&gt;The test has a running live view now, so provide your input by selecting the &lt;code&gt;18 and under&lt;/code&gt; age filter. This will require two steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find the age group drop-down menu&lt;/li&gt;
&lt;li&gt;Choose an item from it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Use the &lt;code&gt;LiveViewTest.element/3&lt;/code&gt; function to find the age group drop-down on the page.&lt;/p&gt;
&lt;p&gt;Assuming the drop-down menu HTML form element has an ID of &lt;code&gt;age-group-filter&lt;/code&gt;, you can target it with &lt;code&gt;element/3&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it filters by age group&amp;quot;, %{conn: conn} do
  {:ok, view, _html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
  html =
    view
    |&amp;gt; element(&amp;quot;#age-group-form&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;element/3&lt;/code&gt; returns &lt;code&gt;Phoenix.LiveViewTest.Element&lt;/code&gt; struct that we can pipe into another &lt;code&gt;LiveViewTest&lt;/code&gt; function in order to simulate the selection of an item and submission of the form:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it filters by age group&amp;quot;, %{conn: conn} do
  {:ok, view, _html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
  html =
    view
    |&amp;gt; element(&amp;quot;#age-group-form&amp;quot;)
    |&amp;gt; render_change(%{&amp;quot;age_group_filter&amp;quot; =&amp;gt; &amp;quot;18 and under&amp;quot;})
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;LiveViewTest.render_change/2&lt;/code&gt; function is one of the functions you&amp;#39;ll use to simulate user interactions when testing live views. It takes an argument of the selected element and some params, triggering a &lt;code&gt;phx-change&lt;/code&gt; event. Here, make sure to call &lt;code&gt;render_change/2&lt;/code&gt; with the exact params that would be sent to the live view when the user selects an age group filter in the UI.&lt;/p&gt;
&lt;p&gt;This event will trigger the associated handler, invoking the reducers that update our socket, and re-rendering the survey results chart with the filtered product rating info.&lt;/p&gt;
&lt;p&gt;With our setup and input in place, we&amp;#39;re ready to write our assertions. The call to &lt;code&gt;render_change/2&lt;/code&gt; will return the re-rendered template. Add an assertion that the re-rendered chart displays the correct data by validating the presence of an updated title for the product&amp;#39;s average rating:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it filters by age group&amp;quot;, %{conn: conn} do
  {:ok, view, _html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
    view
    |&amp;gt; element(&amp;quot;#age-group-form&amp;quot;)
    |&amp;gt; render_change(%{&amp;quot;age_group_filter&amp;quot; =&amp;gt; &amp;quot;18 and under&amp;quot;})
    |&amp;gt; assert =~ &amp;quot;&amp;lt;title&amp;gt;2.00&amp;lt;/title&amp;gt;&amp;quot; # validates that we now display an average rating of 2.00
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once again, the details of our assertion aren&amp;#39;t important. Just understand that when the product ratings are filtered by age group, you can expect to see the element on the page: &lt;code&gt;&amp;lt;title&amp;gt;2.00&amp;lt;/title&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And with that, our first integration test is complete! The &lt;code&gt;LiveViewTest&lt;/code&gt; module provided everything we needed to mount and render a connected live view, target elements within that live view—even elements nested within child components—and assert the state of the view after firing DOM events against those elements.&lt;/p&gt;
&lt;p&gt;The test code is clean and elegantly composed with a simple pipeline. All of it is written in Elixir with ExUnit and &lt;code&gt;LiveViewTest&lt;/code&gt; functions—we didn&amp;#39;t need to bring in any JavaScript dependencies. As a result, writing our test was a straightforward process. We ended up with a reliable test that runs fast and is easy to read.&lt;/p&gt;
&lt;p&gt;This is only a small subset of the &lt;code&gt;LiveViewTest&lt;/code&gt; functions that support LiveView testing, but there are many more &lt;code&gt;LiveViewTest&lt;/code&gt; functions that allow you to send any number of DOM events—blurs, form submissions, live navigation, and more. &lt;a href=&quot;https://hexdocs.pm/phoenix_live_view/Phoenix.LiveViewTest.html&quot;&gt;Learn more about them in the docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before we go, let&amp;#39;s write one more integration test; this time, to exercise interactions between live views.&lt;/p&gt;
&lt;h2&gt;Testing Distributed Updates in LiveView&lt;/h2&gt;
&lt;p&gt;Testing message passing in a distributed application can be painful, but &lt;code&gt;LiveViewTest&lt;/code&gt; makes it easy to test the PubSub-backed real-time features that you can build into your live views. That is because LiveView tests interact with views via process communication. Since PubSub uses simple Elixir message passing, it&amp;#39;s easy to test a live view&amp;#39;s ability to handle such messages: use &lt;code&gt;send/2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this section, we&amp;#39;ll write an integration test that validates the behavior of the &lt;code&gt;AdminDashboardLive&lt;/code&gt; when it receives a specific message over PubSub.&lt;/p&gt;
&lt;h2&gt;The Feature&lt;/h2&gt;
&lt;p&gt;Our &lt;code&gt;AdminDashboardLive&lt;/code&gt; supports the following real-time update feature: when a user anywhere in the world submits a new product rating, then the survey results chart on the admin dashboard updates accordingly, in real-time.&lt;/p&gt;
&lt;p&gt;The following code flow backs this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a user submits a product rating, then a PubSub event, &lt;code&gt;&amp;quot;rating_created&amp;quot;&lt;/code&gt; is broadcast over a topic.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;AdminDashboardLive&lt;/code&gt; view subscribes to that topic and responds to the event by re-rendering the &lt;code&gt;SurveyResultsLive&lt;/code&gt; component with updated data from the database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The details of the code aren&amp;#39;t important for our purposes today—a high-level understanding is all that&amp;#39;s needed to write our test. Let&amp;#39;s get started.&lt;/p&gt;
&lt;h2&gt;The Test&lt;/h2&gt;
&lt;p&gt;Like in our unit test earlier, you can group similar test cases in a single describe block. We already have a &lt;code&gt;describe&lt;/code&gt; block in our integration test module for &lt;code&gt;&amp;quot;Survey Results&amp;quot;&lt;/code&gt;. Since the test of the real-time update feature also describes the behavior of the &lt;code&gt;SurveyResultsLiveComponent&lt;/code&gt;, we&amp;#39;ll add another test case to this same describe block:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;describe &amp;quot;Survey Results&amp;quot; do
  # ...
  test &amp;quot;it updates to display newly created ratings&amp;quot;, %{conn: conn, product: product} do
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, our test case retrieves both the test &lt;code&gt;conn&lt;/code&gt; and the &lt;code&gt;product&lt;/code&gt; from the setup context. Use this product to create a new rating for display.&lt;/p&gt;
&lt;p&gt;Once again, before filling in the body of our test, make a plan. Follow the same three-step process you used for your earlier integration test:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mount and render the connected live view.&lt;/li&gt;
&lt;li&gt;Interact with that live view—in this case, by sending the &lt;code&gt;&amp;quot;rating_created&amp;quot;&lt;/code&gt; message to the live view.&lt;/li&gt;
&lt;li&gt;Re-render the view and verify changes in the resulting HTML.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Start by mounting and rendering the live view with the &lt;code&gt;live/2&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it updates to display newly created ratings&amp;quot;, %{conn: conn, product: product}
  {:ok, view, html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
  assert html =~ &amp;quot;&amp;lt;title&amp;gt;2.50&amp;lt;/title&amp;gt;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we add an intermediate assertion to check the starting state of the product ratings label. Expect to change this value once you create a new rating and send the &lt;code&gt;&amp;quot;rating_created&amp;quot;&lt;/code&gt; message to the live view.&lt;/p&gt;
&lt;p&gt;Next up, provide your input (a two-step process). First, create a new rating for the product:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it updates to display newly created ratings&amp;quot;, %{conn: conn, product: product}
  {:ok, view, html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
  assert html =~ &amp;quot;&amp;lt;title&amp;gt;2.50&amp;lt;/title&amp;gt;&amp;quot;

  # create a new user + demographic and then create a new rating with those records
  user3 = user_fixture(@create_user3_attrs)
  create_demographic(user3)
  create_rating(user3, product, 3)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, send the &lt;code&gt;&amp;quot;rating_created&amp;quot;&lt;/code&gt; message to the live view:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it updates to display newly created ratings&amp;quot;, %{conn: conn, product: product}
  {:ok, view, html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
  assert html =~ &amp;quot;&amp;lt;title&amp;gt;2.50&amp;lt;/title&amp;gt;&amp;quot;

  # create a new user + demographic and then create a new rating with those records
  user3 = user_fixture(@create_user3_attrs)
  create_demographic(user3)
  create_rating(user3, product, 3)

  # send the message to the live view
  send(view.pid, %{event: &amp;quot;rating_created&amp;quot;})
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, use a simple &lt;code&gt;send/2&lt;/code&gt; to mimic the code flow of PubSub broadcasting the &lt;code&gt;&amp;quot;rating_creating&amp;quot;&lt;/code&gt; message. Our live view should respond by re-rendering the &lt;code&gt;SurveyResultsLive&lt;/code&gt; component with fresh data from the DB, including the newly created rating. All we need to do now is add our assertion:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;it updates to display newly created ratings&amp;quot;, %{conn: conn, product: product}
  {:ok, view, html} = live(conn, &amp;quot;/admin-dashboard&amp;quot;)
  assert html =~ &amp;quot;&amp;lt;title&amp;gt;2.50&amp;lt;/title&amp;gt;&amp;quot;

  # create a new user + demographic and then create a new rating with those records
  user3 = user_fixture(@create_user3_attrs)
  create_demographic(user3)
  create_rating(user3, product, 3)
  # send the message to the live view
  send(view.pid, %{event: &amp;quot;rating_created&amp;quot;})
  # give the live view time to re-render
  :timer.sleep(2)
  assert render(view) =~ &amp;quot;&amp;lt;title&amp;gt;2.67&amp;lt;/title&amp;gt;&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&amp;#39;s it! You:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Established your initial state by mounting and rendering the live view with the call to &lt;code&gt;live/2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Provided some input by creating a new rating record and sending a message to the live view with &lt;code&gt;send/2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Validated your expectations by asserting that the re-rendered view had some expected content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our three-step LiveView testing procedure neatly applies to both integration tests that exercise internal live view behavior, and tests that validate the interactions between live view processes.&lt;/p&gt;
&lt;p&gt;Now for wrapping up.&lt;/p&gt;
&lt;h2&gt;Wrap Up: Write Robust and Comprehensive LiveView Tests&lt;/h2&gt;
&lt;p&gt;LiveView empowers you to write robust and comprehensive tests without a huge investment of engineering effort.&lt;/p&gt;
&lt;p&gt;In the previous post, we comprised our individual live views from pipelines of single-purpose reducers. This provided opportunities for deep unit testing to quickly cover lots of scenarios and edge cases. You can even use the same elegant reducer pipelines in your tests to verify the behavior of your live view pipelines.&lt;/p&gt;
&lt;p&gt;This article showed that the &lt;code&gt;LiveViewTest&lt;/code&gt; module provides all the functionality you need to exercise the full range of LiveView interactions in integration tests. We can use the functions in the &lt;code&gt;LiveViewTest&lt;/code&gt; module to apply the same three-step process that guides all of our tests, making it quick and easy to spin up tests for even complex LiveView interactions.&lt;/p&gt;
&lt;p&gt;LiveView is built on top of OTP, and a live view is nothing more than a process. This means you can easily test interactions &lt;em&gt;between&lt;/em&gt; live views by relying on simple message passing.&lt;/p&gt;
&lt;p&gt;The powerful set of tools in your LiveView testing kit is just one of the many reasons that teams can be so productive in LiveView. You and your team can guarantee comprehensive test coverage for your LiveView applications, ensuring that you move quickly while maintaining bug-free code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Using Supervisors to Organize Your Elixir Application</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/08/23/using-supervisors-to-organize-your-elixir-application.html"/>
    <id>https://blog.appsignal.com/2021/08/23/using-supervisors-to-organize-your-elixir-application.html</id>
    <published>2021-08-23T00:00:00+00:00</published>
    <updated>2021-08-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how you can use supervisors to organize your Elixir application.</summary>
    <content type="html">&lt;p&gt;In the previous chapter of this series, we looked at hot code reloading in Elixir and why we should use &lt;code&gt;GenServer&lt;/code&gt;
to implement long-running processes.&lt;/p&gt;
&lt;p&gt;But to organize a whole &lt;em&gt;application&lt;/em&gt;, we need one more building block — &lt;em&gt;supervisors&lt;/em&gt;. Let&amp;#39;s take a look at supervisors in detail.&lt;/p&gt;
&lt;h2&gt;Defining an OTP Application&lt;/h2&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://erlang.org/doc/apps/kernel/application.html&quot;&gt;documentation&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In OTP, application denotes a component implementing some specific functionality, that can be started and stopped as a unit, and that can be reused in other systems. This module interacts with application controller, a process started at every Erlang runtime system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This module contains functions for controlling applications (for example, starting and stopping applications), and functions to access information about applications (for example, configuration parameters).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, an application is a kind of &lt;em&gt;package&lt;/em&gt; that contains reusable modules, has name, version, specific dependencies, etc.&lt;/p&gt;
&lt;p&gt;Mix creates a new application when we run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix new our_new_app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But there is one crucial difference that distinguishes OTP applications from packages in
other languages. OTP applications can be &lt;em&gt;started&lt;/em&gt; and &lt;em&gt;stopped&lt;/em&gt; and have their own running
entities.&lt;/p&gt;
&lt;p&gt;You can usually create such applications in Elixir with the command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix new our_new_app --sup
cd our_new_app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates an additional
file for us: &lt;code&gt;lib/our_new_app/application.ex&lt;/code&gt;.
It implements the so-called &lt;code&gt;application behavior&lt;/code&gt;.
Its primary purpose is to implement &lt;code&gt;start/2&lt;/code&gt; function, which should start a &lt;code&gt;supervision tree&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;What Are Supervision Trees in Elixir?&lt;/h2&gt;
&lt;p&gt;So what is a supervision tree? I use the following analogy: a running OTP system is like
a whole OS with its own lightweight processes.
They start, work, and terminate. As in a real OS, we need a tool that helps us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start the system in the correct order&lt;/li&gt;
&lt;li&gt;Handle abnormal situations when a process dies due to some errors&lt;/li&gt;
&lt;li&gt;Stop the system correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In a real OS, we have &lt;em&gt;Systemd&lt;/em&gt; (on some Linux OSes) or &lt;em&gt;launchd&lt;/em&gt; on MacOS. In OTP,
there are supervisors and &lt;code&gt;Supervisor&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;We can organize our processes in the following way using supervisors:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-08/suptree.png&quot; alt=&quot;Supervision Tree&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Leaf processes in this scheme are generally &lt;code&gt;GenServer&lt;/code&gt; or similar processes.&lt;/p&gt;
&lt;p&gt;As in Systemd, if a process fails, we can choose to do nothing. Another option is to restart the process
over and over again until it completes normally, or together with sibling processes.&lt;/p&gt;
&lt;p&gt;Earlier, in Erlang, it was tricky to build supervision trees, but Elixir helps
us &lt;strong&gt;a lot&lt;/strong&gt; with this.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also worth noting that there is some &lt;a href=&quot;https://hexdocs.pm/elixir/Supervisor.html&quot;&gt;good
documentation available about supervisors&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Connecting GenServers to a Supervision Tree&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s again look at what mix created for us in &lt;code&gt;lib/our_new_app/application.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def start(_type, _args) do
    children = [
      # Starts a worker by calling: OurNewApp.Worker.start_link(arg)
      # {OurNewApp.Worker, arg}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: OurNewApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It starts a supervisor and clearly shows how to run our worker as a child.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s do that. We will be able to increment a given number periodically and report its state on demand in our sample process.&lt;/p&gt;
&lt;p&gt;First, create a &lt;code&gt;GenServer&lt;/code&gt; in &lt;code&gt;lib/our_new_app/counter.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule OurNewApp.Counter do
  use GenServer
  require Logger

  @interval 100

  def start_link(start_from, opts \\ []) do
    GenServer.start_link(__MODULE__, start_from, opts)
  end

  def get(pid) do
    GenServer.call(pid, :get)
  end

  def init(start_from) do
    st = %{
      current: start_from,
      timer: :erlang.start_timer(@interval, self(), :tick)
    }

    {:ok, st}
  end

  def handle_call(:get, _from, st) do
    {:reply, st.current, st}
  end

  def handle_info({:timeout, _timer_ref, :tick}, st) do
    new_timer = :erlang.start_timer(@interval, self(), :tick)
    :erlang.cancel_timer(st.timer)

    {:noreply, %{st | current: st.current + 1, timer: new_timer}}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This server increments a given number every 100ms and can report its state via &lt;code&gt;OurNewApp.Counter.get/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex -S mix
...
iex(1)&amp;gt; {:ok, pid} = OurNewApp.Counter.start_link(10000)
{:ok, #PID&amp;lt;0.182.0&amp;gt;}
iex(2)&amp;gt; OurNewApp.Counter.get(pid)
10136
iex(3)&amp;gt; OurNewApp.Counter.get(pid)
10146
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&amp;#39;s integrate our server as a child. Update &lt;code&gt;start/2&lt;/code&gt; function in &lt;code&gt;lib/our_new_app/application.ex&lt;/code&gt; to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def start(_type, _args) do
    children = [
      {OurNewApp.Counter, 10000}
    ]

    opts = [strategy: :one_for_one, name: OurNewApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;We see that our process starts automatically:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex -S mix
...
iex(1)&amp;gt; [{_, pid, _, _}] = Supervisor.which_children(OurNewApp.Supervisor)
[{OurNewApp.Counter, #PID&amp;lt;0.141.0&amp;gt;, :worker, [OurNewApp.Counter]}]
iex(2)&amp;gt; OurNewApp.Counter.get(pid)
10119
iex(3)&amp;gt; Process.exit(pid, :shutdown)
true
iex(4)&amp;gt; Supervisor.which_children(OurNewApp.Supervisor)
[{OurNewApp.Counter, #PID&amp;lt;0.146.0&amp;gt;, :worker, [OurNewApp.Counter]}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We queried the supervisor&amp;#39;s children with &lt;code&gt;Supervisor.which_children/1&lt;/code&gt;. We also see
that our counter process restarted after we stopped it.&lt;/p&gt;
&lt;p&gt;Our process tree now looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-08/suptree_counter.png&quot; alt=&quot;Supervision Tree with Counter&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Adding GenServers to Custom Supervisors&lt;/h2&gt;
&lt;p&gt;Now let&amp;#39;s make a special supervisor for our counter processes. Later, we&amp;#39;ll
see why we may want to do that. Our supervision tree will look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-08/suptree_counter_with_sups.png&quot; alt=&quot;Supervision Tree with Counters and their own supervisor&quot;/&gt;&lt;/p&gt;
&lt;p&gt;First, we should make a callback module for our new special supervisor. Let&amp;#39;s add &lt;code&gt;lib/our_new_app/counter_sup.ex&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule OurNewApp.CounterSup do
  use Supervisor

  def start_link(start_numbers) do
    Supervisor.start_link(__MODULE__, start_numbers, name: __MODULE__)
  end

  @impl true
  def init(start_numbers) do
    children =
      for start_number &amp;lt;- start_numbers do
        # We can&amp;#39;t just use `{OurNewApp.Counter, start_number}`
        # because we need different ids for children

        Supervisor.child_spec({OurNewApp.Counter, start_number}, id: start_number)
      end

    Supervisor.init(children, strategy: :one_for_one)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We must also update children for the main application supervisor in &lt;code&gt;lib/our_new_app/application.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def start(_type, _args) do
    children = [
      {OurNewApp.CounterSup, [10000, 20000]}
    ]

    opts = [strategy: :one_for_one, name: OurNewApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s see what we get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex -S mix
...
iex(1)&amp;gt; Supervisor.which_children(OurNewApp.Supervisor)
[{OurNewApp.CounterSup, #PID&amp;lt;0.161.0&amp;gt;, :supervisor, [OurNewApp.CounterSup]}]
iex(2)&amp;gt; Supervisor.which_children(OurNewApp.CounterSup)
[
  {20000, #PID&amp;lt;0.163.0&amp;gt;, :worker, [OurNewApp.Counter]},
  {10000, #PID&amp;lt;0.162.0&amp;gt;, :worker, [OurNewApp.Counter]}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s just what we need: &lt;code&gt;OurNewApp.Supervisor&lt;/code&gt; has &lt;code&gt;OurNewApp.CounterSup&lt;/code&gt; as its child
and &lt;code&gt;OurNewApp.CounterSup&lt;/code&gt; has two &lt;code&gt;OurNewApp.Counter&lt;/code&gt; children.&lt;/p&gt;
&lt;p&gt;Many developers consider custom supervisors tricky and avoid using them.
So let&amp;#39;s do some simple exercises to get more acquainted with them.&lt;/p&gt;
&lt;p&gt;First, we&amp;#39;ll add a third counter to our counter supervisor at runtime:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;
iex(3)&amp;gt; new_child_spec = Supervisor.child_spec({OurNewApp.Counter, 30000}, id: 30000)
%{id: 30000, start: {OurNewApp.Counter, :start_link, [30000]}}
iex(4)&amp;gt; Supervisor.start_child(OurNewApp.CounterSup, new_child_spec)
{:ok, #PID&amp;lt;0.169.0&amp;gt;}
iex(5)&amp;gt; Supervisor.which_children(OurNewApp.CounterSup)
[
  {30000, #PID&amp;lt;0.169.0&amp;gt;, :worker, [OurNewApp.Counter]},
  {20000, #PID&amp;lt;0.163.0&amp;gt;, :worker, [OurNewApp.Counter]},
  {10000, #PID&amp;lt;0.162.0&amp;gt;, :worker, [OurNewApp.Counter]}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was easy! With &lt;code&gt;Supervisor.delete_child/2&lt;/code&gt;, &lt;code&gt;Supervisor.restart_child/2&lt;/code&gt;, etc.,
we can easily manipulate the supervisor&amp;#39;s children.&lt;/p&gt;
&lt;p&gt;Secondly, instead of adding one worker to the existing tree, let&amp;#39;s try adding a subtree with its
own children (without a special module for the subtree supervisor):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(6)&amp;gt; children_specs = for n &amp;lt;- [10000, 20000, 30000], do: Supervisor.child_spec({OurNewApp.Counter, n}, id: n)
[
  %{id: 10000, start: {OurNewApp.Counter, :start_link, [10000]}},
  %{id: 20000, start: {OurNewApp.Counter, :start_link, [20000]}},
  %{id: 30000, start: {OurNewApp.Counter, :start_link, [30000]}}
]
iex(7)&amp;gt; hand_crafted_sup_spec = %{
...(7)&amp;gt;     id: :hand_crafted_sup,
...(7)&amp;gt;     start: {Supervisor, :start_link, [children_specs, [strategy: :one_for_one]]},
...(7)&amp;gt;     type: :supervisor,
...(7)&amp;gt;     restart: :permanent,
...(7)&amp;gt;     shutdown: 5000
...(7)&amp;gt; }
...
iex(8)&amp;gt; Supervisor.start_child(OurNewApp.Supervisor, hand_crafted_sup_spec)
{:ok, #PID&amp;lt;0.204.0&amp;gt;}
iex(9)&amp;gt; Supervisor.which_children(OurNewApp.Supervisor)
[
  {:hand_crafted_sup, #PID&amp;lt;0.204.0&amp;gt;, :supervisor, [Supervisor]},
  {OurNewApp.CounterSup, #PID&amp;lt;0.161.0&amp;gt;, :supervisor, [OurNewApp.CounterSup]}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following took place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;hand_crafted_sup_spec&lt;/code&gt; was constructed, which started &lt;code&gt;Supervisor.start_link&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;We told our main supervisor to start a child with this spec&lt;/li&gt;
&lt;li&gt;The main supervisor started with &lt;code&gt;children_specs&lt;/code&gt; parameters&lt;/li&gt;
&lt;li&gt;It started counters from &lt;code&gt;children_specs&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We could do this in another way: tell our main supervisor to launch
an empty child supervisor, then add counters one by one to this child supervisor.&lt;/p&gt;
&lt;p&gt;The process tree at the end of the experiment should look like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-08/sups_handcrafted.png&quot; alt=&quot;Supervision Tree with handcrafted supervisor&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Examples of Custom Supervisor Usage&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s see what happens if we terminate our app.&lt;/p&gt;
&lt;p&gt;First, add some logging to &lt;code&gt;lib/our_new_app/counter.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def terminate(reason, st) do
    Logger.info(&amp;quot;terminating with #{inspect(reason)}, counter is #{st.current}&amp;quot;)
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also enable the &lt;code&gt;:trap_exit&lt;/code&gt; flag for our counters, so that we can handle
process termination — &lt;a href=&quot;https://hexdocs.pm/elixir/1.12/GenServer.html#c:terminate/2&quot;&gt;see &lt;code&gt;terminate&lt;/code&gt; callback documentation&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def init(start_from) do
    Process.flag(:trap_exit, true)

    st = %{
    ...
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if we stop our application in the iex session, we see:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex -S mix
...
iex(1)&amp;gt; Application.stop(:our_new_app)
19:35:43.544 [info]  terminating with :shutdown, counter is 20049
19:35:43.548 [info]  terminating with :shutdown, counter is 10050
19:35:43.548 [info]  Application our_new_app exited: :stopped
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Imagine that we have to implement a &lt;em&gt;graceful&lt;/em&gt; shutdown. The condition of
gracefulness is to count up until we reach numbers divisible by 10 (10, 20, 30, etc) before shutdown.&lt;/p&gt;
&lt;p&gt;Of course, in our simple example, we may just send ticks to count to the nearest
number divisible by 10 in &lt;code&gt;terminate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead, imagine that these events are
external end emulate some metrics that we would prefer to aggregate consistently.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s add the possibility of a graceful restart to the &lt;code&gt;OurNewApp.Counter&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule OurNewApp.Counter do
  use GenServer
  require Logger

  @interval 100

  def start_link(start_from) do
    GenServer.start_link(__MODULE__, start_from)
  end

  def get(pid) do
    GenServer.call(pid, :get)
  end

  def stop_gracefully(pid) do
    GenServer.call(pid, :stop_gracefully)
  end

  def init(start_from) do
    Process.flag(:trap_exit, true)

    st = %{
      current: start_from,
      timer: :erlang.start_timer(@interval, self(), :tick),
      terminator: nil
    }

    {:ok, st}
  end

  def handle_call(:get, _from, st) do
    {:reply, st.current, st}
  end

  def handle_call(:stop_gracefully, from, st) do
    if st.terminator do
      {:reply, :already_stopping, st}
    else
      {:noreply, %{st | terminator: from}}
    end
  end

  def handle_info({:timeout, _timer_ref, :tick}, st) do
    :erlang.cancel_timer(st.timer)

    new_current = st.current + 1

    if st.terminator &amp;amp;&amp;amp; rem(new_current, 10) == 0 do
      # we are terminating
      GenServer.reply(st.terminator, :ok)
      {:stop, :normal, %{st | current: new_current, timer: nil}}
    else
      new_timer = :erlang.start_timer(@interval, self(), :tick)
      {:noreply, %{st | current: new_current, timer: new_timer}}
    end
  end

  def terminate(reason, st) do
    Logger.info(&amp;quot;terminating with #{inspect(reason)}, counter is #{st.current}&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;terminator&lt;/code&gt; field to the state that keeps the address of the party that wants to stop the server&lt;/li&gt;
&lt;li&gt;Set this field in the &lt;code&gt;stop_gracefully&lt;/code&gt; handler&lt;/li&gt;
&lt;li&gt;Continue counting until we get to a number divisible by 10&lt;/li&gt;
&lt;li&gt;Respond to the terminating party and stop the server upon obtaining this number.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#39;s see how that works for a single process:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex -S mix
Erlang/OTP 23 [erts-11.0.4] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [hipe]

iex(1)&amp;gt; {:ok, pid} = OurNewApp.Counter.start_link(10000)
{:ok, #PID&amp;lt;0.167.0&amp;gt;}
iex(2)&amp;gt; OurNewApp.Counter.stop_gracefully(pid)
:ok
iex(3)&amp;gt;
20:03:13.061 [info]  terminating with :normal, counter is 10120
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything works fine. But what stops all counters gracefully? As we see in the &lt;a href=&quot;https://erlang.org/doc/apps/kernel/application.html#Module:prep_stop-1&quot;&gt;OTP docs&lt;/a&gt;,
&lt;code&gt;OurNewApp.Application.prep_stop&lt;/code&gt; is called (if it exists) before the application stops.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s add the desired functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  @impl true
  def prep_stop(st) do
    stop_tasks =
      for {_, pid, _, _} &amp;lt;- Supervisor.which_children(OurNewApp.CounterSup) do
        Task.async(fn -&amp;gt;
          :ok = OurNewApp.Counter.stop_gracefully(pid)
        end)
      end

    Task.await_many(stop_tasks)

    st
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also set &lt;code&gt;:restart&lt;/code&gt; option to &lt;code&gt;:transient&lt;/code&gt; in &lt;code&gt;OurNewApp.CounterSup&lt;/code&gt; so that our counters do not restart after graceful shutdown:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Supervisor.child_spec({OurNewApp.Counter, {start_number, 200}},
  id: start_number,
  restart: :transient
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try to stop the app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex -S mix
iex(1)&amp;gt; Application.stop(:our_new_app)

20:24:02.958 [info]  terminating with :normal, counter is 10260

20:24:02.958 [info]  terminating with :normal, counter is 20260

20:24:02.962 [info]  Application our_new_app exited: :stopped
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we only stop at numbers divisible by 10.&lt;/p&gt;
&lt;p&gt;Using a special supervisor for our counters makes it possible to &amp;quot;find&amp;quot; all the instances
quickly and operate with them. This is extremely important when applications go through
start/stop stages.&lt;/p&gt;
&lt;h2&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;I hope you&amp;#39;ve managed to wrap your head around supervisors in Elixir, and have found this article helpful, alongside the previous article on hot code reloading.&lt;/p&gt;
&lt;p&gt;There is another, even more complicated stage in an application life cycle: application code upgrades. We&amp;#39;ll leave that for the third and final part of this series.&lt;/p&gt;
&lt;p&gt;Until then, enjoy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>An Introduction to Testing LiveView in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/08/17/an-introduction-to-liveview-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/08/17/an-introduction-to-liveview-in-elixir.html</id>
    <published>2021-08-17T00:00:00+00:00</published>
    <updated>2021-08-17T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this two-part series, you&#039;ll get a comprehensive overview of how to test your LiveView applications in Elixir.</summary>
    <content type="html">&lt;p&gt;In this two-part series, you&amp;#39;ll get a comprehensive overview of everything you need to know to test your LiveView applications in Elixir.&lt;/p&gt;
&lt;p&gt;In Part I, I&amp;#39;ll introduce you to LiveView testing guidelines and you&amp;#39;ll write some flexible and elegant LiveView unit tests. In Part II, you&amp;#39;ll write interactive LiveView tests that validate a full set of live view behaviors.&lt;/p&gt;
&lt;h2&gt;Introducing LiveView&amp;#39;s Powerful Testing Tools&lt;/h2&gt;
&lt;p&gt;If you&amp;#39;ve worked with LiveView, you&amp;#39;ve already experienced how productive you and your team can be with a framework that lets you build interactive UIs, while keeping your brain firmly focused on the server-side.&lt;/p&gt;
&lt;p&gt;Testing LiveView is no different—you can exercise the full functionality of your live views with pure Elixir tests written in ExUnit through the help of the &lt;code&gt;LiveViewTest&lt;/code&gt; module. So your tests are fast, concurrent, and continue to keep your focus firmly on server-side code.&lt;/p&gt;
&lt;p&gt;LiveView&amp;#39;s testing framework empowers you to quickly write robust and comprehensive tests that are highly stable. With a high degree of test coverage firmly in hand, you and your team will be able to move quickly and confidently when building LiveView applications.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll explore more on what makes LiveView testing so powerful, understand the principles for approaching live view tests, and write some unit tests.&lt;/p&gt;
&lt;p&gt;In the next post, you&amp;#39;ll write more advanced integration tests, and even test a distributed, real-time update feature in LiveView.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s get going!&lt;/p&gt;
&lt;h2&gt;Principles for Testing LiveView in Elixir&lt;/h2&gt;
&lt;p&gt;The basic principles for testing LiveView don&amp;#39;t differ much from testing in other languages and frameworks. Any given test has three steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up preconditions,&lt;/li&gt;
&lt;li&gt;Provide a stimulus, and&lt;/li&gt;
&lt;li&gt;Compare an actual response to expectations.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&amp;#39;re going to write two kinds of tests—unit tests and integration tests—and we&amp;#39;ll use this procedure for both types. Let&amp;#39;s dig a little deeper into what these two kinds of tests look like in LiveView.&lt;/p&gt;
&lt;h2&gt;Unit Tests in LiveView&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;unit test&lt;/strong&gt; is designed to test an individual unit of code. Pure unit tests call one function at a time and then check expectations with one or more assertions.&lt;/p&gt;
&lt;p&gt;Unit tests encourage &lt;em&gt;depth&lt;/em&gt;. Such tests don&amp;#39;t require much ceremony, so you can cover lots of scenarios quickly and easily. Unit tests also allow &lt;em&gt;loose coupling&lt;/em&gt; because they don&amp;#39;t rely on specific interactions between different parts of your code or your system.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll write some unit tests today to verify the behavior of the independent reducer functions that our live view implements to establish socket state under different conditions.&lt;/p&gt;
&lt;h2&gt;Integration Tests in LiveView&lt;/h2&gt;
&lt;p&gt;Integration tests, on the other hand, validate the interactions between different parts of your system. This kind of test offers testing &lt;em&gt;breadth&lt;/em&gt; by exercising a wider swath of your application. The cost is tighter coupling since integration tests rely on specific interactions between parts of your system.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll write two integration tests that help us verify the behavior of the overall live view. Our first integration test will validate the interactions &lt;em&gt;within&lt;/em&gt; a single live view process, and the second will verify a PubSub-backed interaction &lt;em&gt;between&lt;/em&gt; two live views.&lt;/p&gt;
&lt;p&gt;You might be surprised to hear that none of the tests we&amp;#39;ll write in this post will be testing JavaScript. This is because the LiveView framework is specifically designed to handle JavaScript for us. For the average live view that &lt;em&gt;doesn&amp;#39;t&lt;/em&gt; implement any custom JavaScript, there&amp;#39;s no need to test JS code or even to write any tests that use JavaScript. We can trust that the JS in the LiveView framework itself works as expected.&lt;/p&gt;
&lt;p&gt;We&amp;#39;re just about ready to start writing our very first LiveView test, and we&amp;#39;ll start with some unit tests.&lt;/p&gt;
&lt;p&gt;In general, it&amp;#39;s a good idea to start with unit test coverage before moving on to integration testing. By exercising individual functions in unit tests with many different inputs, you can exhaustively cover corner cases. This lets you write a smaller number of integration tests to confirm that the complex interactions of the system work as you expect them to.&lt;/p&gt;
&lt;p&gt;So, to recap, we can apply the following principles to LiveView testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Follow the three-step procedure of setting up preconditions, providing a stimulus, and validating expectations.&lt;/li&gt;
&lt;li&gt;Write both unit and integration tests.&lt;/li&gt;
&lt;li&gt;Don&amp;#39;t test JavaScript you didn&amp;#39;t write.&lt;/li&gt;
&lt;li&gt;Start by writing comprehensive unit tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alright, with these principles in hand, we&amp;#39;re ready to start testing.&lt;/p&gt;
&lt;h2&gt;How to Unit Test LiveView&lt;/h2&gt;
&lt;p&gt;In this section, we&amp;#39;ll use our three-step testing procedure to write a few unit tests for the behavior of a LiveView component.&lt;/p&gt;
&lt;p&gt;We happen to be testing a LiveView component here, but the tests you&amp;#39;ll learn how to write here apply to both components and regular live views.&lt;/p&gt;
&lt;p&gt;As you build your tests, we&amp;#39;ll look at how composing our LiveView component out of single-purpose reducer functions helps make the code easy to test.&lt;/p&gt;
&lt;h3&gt;The Feature&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;The testing examples that we&amp;#39;ll be looking at in this post are drawn from the &amp;quot;Test Your Live Views&amp;quot; chapter in my book, &lt;a href=&quot;https://pragprog.com/titles/liveview/programming-phoenix-liveview/&quot;&gt;Programming LiveView&lt;/a&gt;, co-authored with Bruce Tate. Check it out for an even deeper dive into LiveView testing and so much more.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this example, we have an online game store that allows users to browse and review products. We provide our users with a survey that asks them for some basic demographic input, along with star ratings of each game. A LiveView component, &lt;code&gt;SurveyResultsLive&lt;/code&gt;, displays this survey&amp;#39;s results as a chart that graphs the games and their star ratings on a scale of 1 to 5. Here&amp;#39;s a look at the component UI:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-08/survey-results-age-group-filtered.png&quot; alt=&quot;survey results chart&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Notice the age group filter drop-down menu at the top of the chart. Users can select an age group by which to filter the survey results. When the page loads, the value of the age group filter should default to &amp;quot;all&amp;quot;, and the chart should show all of the results. But when a user selects an age group from the menu, an event will be sent to the live view, and the results will be filtered.&lt;/p&gt;
&lt;p&gt;Before we write our test, let&amp;#39;s take a look at the code we&amp;#39;re testing.&lt;/p&gt;
&lt;h3&gt;The Code&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;update/2&lt;/code&gt; function of the &lt;code&gt;SurveyResultsLive&lt;/code&gt; component sets the initial state with the help of some single-purpose reducer functions. A reducer function is a function that takes in some input of some type and returns an updated version of that input.&lt;/p&gt;
&lt;p&gt;We can use single-purpose reducer functions that take in a live view socket, add some state to that socket, and return an updated socket, to build nice clean pipelines for managing state in LiveView. Here&amp;#39;s our &lt;code&gt;update/2&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;  def update(assigns, socket) do
    {:ok,
     socket
     |&amp;gt; assign(assigns)
     |&amp;gt; assign_age_group_filter()
     |&amp;gt; assign_products_with_average_ratings()
     |&amp;gt; assign_chart_svg()}
  end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The details of most of these reducer functions are not important, but we will take a closer look at the &lt;code&gt;assign_age_group_filter&lt;/code&gt; reducer right now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt; def assign_age_group_filter(socket) do
  assign(socket, :age_group_filter, &amp;quot;all&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our reducer is pretty simple. It adds a key &lt;code&gt;:age_group_filter&lt;/code&gt; to the socket and sets it to the default value of &amp;quot;all&amp;quot;.&lt;/p&gt;
&lt;p&gt;However, we need a second version of this function to call in the &lt;code&gt;handle_event/3&lt;/code&gt; that gets invoked when the user selects an age group from the drop-down menu. This version of the function should take the selected age group from the event and set &lt;em&gt;that&lt;/em&gt; as the value in the &lt;code&gt;:age_group_filter&lt;/code&gt; key of socket assigns, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def handle_event(&amp;quot;age_group_filter&amp;quot;, %{&amp;quot;age_group_filter&amp;quot; =&amp;gt; age_group_filter}, socket) do
  {:noreply,
    socket
    |&amp;gt; assign_age_group_filter(age_group_filter)
    |&amp;gt; assign_products_with_average_ratings()
    #...
    }
end

def assign_age_group_filter(socket, age_group_filter) do
  assign(socket, :age_group_filter, age_group_filter)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, with a basic understanding of this code in place, we&amp;#39;re ready to write our test.&lt;/p&gt;
&lt;h3&gt;The Test&lt;/h3&gt;
&lt;p&gt;First off, we need to implement our test module in a file, &lt;code&gt;gamestore/test/gamestor_web/live/survey_results_live_test.exs&lt;/code&gt;, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GamestoreWeb.SurveyResultsLiveTest do
  use ExUnit.Case
  alias GamestoreWeb.SurveyResultsLive
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&amp;#39;re aliasing the &lt;code&gt;SurveyResultsLive&lt;/code&gt; component to make it easier to refer to in our tests and we&amp;#39;re using the &lt;code&gt;ExUnit.Case&lt;/code&gt; behavior to gain access to ExUnit testing functionality. We&amp;#39;re not importing any other code or even any other testing utilities since we can write our unit test in pure Elixir without any database interactions.&lt;/p&gt;
&lt;p&gt;Next up, we&amp;#39;ll establish a fixture that we can share across test cases. Every test will assert some expectations about a LiveView socket. So, we&amp;#39;ll add a fixture that returns a socket, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GamestoreWeb.SurveyResultsLiveTest do
  use ExUnit.Case
  alias GamestoreWeb.SurveyResultsLive

  defp create_socket(_) do
    %{socket: %Phoenix.LiveView.Socket{}}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that our test module is defined and we&amp;#39;ve implemented a helper function to create test data (i.e. our socket), we&amp;#39;re ready to write our very first test.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll start with a test that verifies the default socket state when no age group filter is supplied. Open up a describe block and add a call to the &lt;code&gt;setup/1&lt;/code&gt; function with a call to the helper function that returns a socket struct, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GamestoreWeb.SurveyResultsLiveTest do
  use ExUnit.Case
  alias GamestoreWeb.SurveyResultsLive

  defp create_socket(_) do
    %{socket: %Phoenix.LiveView.Socket{}}
  end

  describe &amp;quot;Socket state&amp;quot; do
    setup do
      create_socket()
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures the &lt;code&gt;socket&lt;/code&gt; will be available to all of our test cases. Now we&amp;#39;re ready to write the test itself.&lt;/p&gt;
&lt;p&gt;Create a test block within the &lt;code&gt;describe&lt;/code&gt; block that pattern matches the &lt;code&gt;socket&lt;/code&gt; out of the context we created in the setup function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule GamestoreWeb.SurveyResultsLiveTest do
  use ExUnit.Case
  alias GamestoreWeb.SurveyResultsLive

  defp create_socket(_) do
    %{socket: %Phoenix.LiveView.Socket{}}
  end

  describe &amp;quot;Socket state&amp;quot; do
    setup do
      create_socket()
    end

    test &amp;quot;when no age group filter is provided&amp;quot;, %{socket: socket} do
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s pause and think through what we&amp;#39;re testing here and try to understand what behavior we &lt;em&gt;expect&lt;/em&gt; to see. This test covers the function &lt;code&gt;assign_age_group_filter/1&lt;/code&gt;. If it&amp;#39;s working correctly, the socket should contain a key of &lt;code&gt;:age_group_filter&lt;/code&gt; that points to a value of &lt;code&gt;&amp;quot;all&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now that we understand our expectation, let&amp;#39;s finish up the test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;when no age group filter is provided&amp;quot;, %{socket: socket} do
  socket =
    socket
    |&amp;gt; SurveyResultsLive.assign_age_group_filter()

  assert
    socket.assigns.age_group_filter == &amp;quot;all&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great! We can see that our three-step testing process is represented here like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set up preconditions by calling the &lt;code&gt;setup&lt;/code&gt; function to establish our initial socket and make it available to the test case.&lt;/li&gt;
&lt;li&gt;Provide the stimulus by calling the &lt;code&gt;SurveyResultsLive.assign_age_group_filter/1&lt;/code&gt; function to return a new socket.&lt;/li&gt;
&lt;li&gt;Validate the expectations regarding the new socket&amp;#39;s state.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#39;s quickly add another test that validates the socket state when an age group filter &lt;em&gt;is&lt;/em&gt; provided:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;when age group filter is provided&amp;quot;, %{socket: socket} do
  socket =
    socket
    |&amp;gt; SurveyResultsLive.assign_age_group_filter(&amp;quot;18 and under&amp;quot;)

  assert
    socket.assigns.age_group_filter == &amp;quot;18 and under&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Simple enough. Let&amp;#39;s tackle a more complex scenario. Recall that our &lt;code&gt;update/2&lt;/code&gt; and &lt;code&gt;handle_event/3&lt;/code&gt; functions invoke &lt;code&gt;assign_age_group_filter&lt;/code&gt; and then pipe the resulting socket into a call to the &lt;code&gt;assign_products_with_average_ratings/1&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;We won&amp;#39;t worry about the details of this function for now. Just know that it queries for the product ratings given the filter info that is set in socket assigns. The composable nature of our single-purpose reducer functions lets us write multi-stage unit tests that exercise the behavior of the reducer pipeline as a whole.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s write a test that validates the product ratings assignment under different filter conditions.&lt;/p&gt;
&lt;p&gt;Start by defining a new test and providing it with the &lt;code&gt;socket&lt;/code&gt; from the setup function, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;ratings are filtered by age group&amp;quot;, %{socket: socket} do

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we&amp;#39;ll set the socket state with a call to &lt;code&gt;SurveyResultsLive.assign_age_group_filter/1&lt;/code&gt; and validate that the products with average ratings are set correctly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;ratings are filtered by age group&amp;quot;, %{socket: socket} do
  socket =
    socket
    |&amp;gt; SurveyResultsLive.assign_age_group_filter()
    |&amp;gt; SurveyResultsLive.assign_products_with_average_ratings()

  assert
    socket.assigns.products_with_average_ratings == all_products_with_ratings # don&amp;#39;t worry about the value of `all_products_with_ratings`, just assume its a list of all products with their average ratings
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great! Next up, we&amp;#39;ll update the socket&amp;#39;s &lt;code&gt;:age_group_filter&lt;/code&gt; state with the help of the &lt;code&gt;assign_age_group_filter/2&lt;/code&gt; reducer function, pipe the updated socket into &lt;em&gt;another&lt;/em&gt; call to &lt;code&gt;assign_products_with_average_ratings/1&lt;/code&gt;, and validate another assertion:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;ratings are filtered by age group&amp;quot;, %{socket: socket} do
  socket =
    socket
    |&amp;gt; SurveyResultsLive.assign_age_group_filter()
    |&amp;gt; SurveyResultsLive.assign_products_with_average_ratings()

  assert
    socket.assigns.products_with_average_ratings == all_products_with_ratings # don&amp;#39;t worry about the value of `all_products_with_ratings`, just assume its a list of all products with their average ratings

  socket =
    socket
    |&amp;gt; SurveyResultsLive.assign_age_group_filter(&amp;quot;18 and under&amp;quot;)
    |&amp;gt; SurveyResultsLive.assign_products_with_average_ratings()

  assert
    socket.assigns.products_with_average_ratings == filtered_products_with_ratings # don&amp;#39;t worry about the value of `filtered_products_with_ratings`, assume it&amp;#39;s a list of all products with their average ratings provided by users in the specified age group
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This test works, but it&amp;#39;s pretty verbose. We can clean it up by taking inspiration from the clean, readable reducer pipelines we used in the &lt;code&gt;SurveyResultsLive&lt;/code&gt; component to set state. Let&amp;#39;s start by defining a helper function for use in our test, &lt;code&gt;assert_keys&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp assert_keys(socket, key, value) do
  assert socket.assigns[key] == value
  socket
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function takes in a socket, performs a test assertion, and then returns the socket. Since it takes in a socket and returns a socket, it behaves just like a reducer. Now, we can use our helper function to string together a beautiful, clean testing pipeline, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;ratings are filtered by age group&amp;quot;, %{socket: socket} do
  socket
  |&amp;gt; SurveyResultsLive.assign_age_group_filter()
  |&amp;gt; SurveyResultsLive.assign_products_with_average_ratings()
  |&amp;gt; assert_keys(:products_with_average_ratings, all_products_with_ratings)
  |&amp;gt; SurveyResultsLive.assign_age_group_filter(&amp;quot;18 and under&amp;quot;)
  |&amp;gt; SurveyResultsLive.assign_products_with_average_ratings()
  |&amp;gt; assert_keys(:products_with_average_ratings, filtered_products_with_ratings)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much better. Our usage of small, single-purpose reducer functions not only helped us write a clean, readable, and organized live view, it also helped us quickly write comprehensive unit tests.&lt;/p&gt;
&lt;p&gt;Furthermore, we were able to string together a &lt;em&gt;test&lt;/em&gt; pipeline that functions just like the real reducer pipeline in our live view. This let us write a unit test that exercised the pipeline&amp;#39;s functionality as a whole.&lt;/p&gt;
&lt;p&gt;You can easily imagine writing additional test cases for the other reducer functions implemented in the LiveView component, and additional pipeline tests that exercise the behavior of the reducer pipelines used in the &lt;code&gt;update/2&lt;/code&gt; and &lt;code&gt;handle_event/3&lt;/code&gt; functions of our component.&lt;/p&gt;
&lt;p&gt;We applied our three-step testing process to end up with clean, readable test cases for both kinds of unit tests.&lt;/p&gt;
&lt;h2&gt;Next Up&lt;/h2&gt;
&lt;p&gt;In the next post, we&amp;#39;ll leverage this same process to write some integration tests that verify the internal interactions within a single live view and the interactions &lt;em&gt;between&lt;/em&gt; live view processes.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A Guide to Hot Code Reloading in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/07/27/a-guide-to-hot-code-reloading-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/07/27/a-guide-to-hot-code-reloading-in-elixir.html</id>
    <published>2021-07-27T00:00:00+00:00</published>
    <updated>2021-07-27T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how to use hot code reloading and updates in your production code upgrade in Elixir.</summary>
    <content type="html">&lt;p&gt;When building software, Elixir (or Erlang) offers great benefits, including concurrency, scalability and reliability.&lt;/p&gt;
&lt;p&gt;In this series, we will examine how to make the most of these benefits in your production code upgrades. This article will focus on hot code reloading and upgrades. But before we dive in, let&amp;#39;s quickly define OTP.&lt;/p&gt;
&lt;h2&gt;What Is OTP in Elixir?&lt;/h2&gt;
&lt;p&gt;Formally, &lt;a href=&quot;https://en.wikipedia.org/wiki/Open_Telecom_Platform&quot;&gt;Erlang/OTP&lt;/a&gt;
is a specific implementation of &lt;a href=&quot;https://blog.stenmans.org/theBeamBook/#P-ERTS&quot;&gt;Erlang Runtime System&lt;/a&gt;, i.e. a set of libraries, compilers and a VM implementation.&lt;/p&gt;
&lt;p&gt;Informally, &lt;em&gt;OTP&lt;/em&gt; often denotes a set of principles to build robust apps in Erlang and the
corresponding set of built-in libraries.&lt;/p&gt;
&lt;h2&gt;Hot Code Reload: Tackling the Uncertainties&lt;/h2&gt;
&lt;p&gt;There is a bit of uncertainty about this concept.&lt;/p&gt;
&lt;p&gt;When we speak of &lt;em&gt;hot code reload&lt;/em&gt; or &lt;em&gt;hot code upgrade&lt;/em&gt;, we usually mean an ability to change a running process behavior
without any negative impact on that process. For example, we may change the behavior of a process that holds
a TCP connection without terminating this connection.&lt;/p&gt;
&lt;p&gt;Uncertainty comes in with scaling — the question is if we can upgrade:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a module&lt;/li&gt;
&lt;li&gt;a package (an &lt;em&gt;application&lt;/em&gt; in terms of OTP)&lt;/li&gt;
&lt;li&gt;a whole running instance (a &lt;em&gt;release&lt;/em&gt; in terms of OTP)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OTP offers tools for upgrading at any scale. In this article, we will consider application
level upgrades.&lt;/p&gt;
&lt;h3&gt;How Are OTP and Hot Code Upgrades Related?&lt;/h3&gt;
&lt;p&gt;As we will see, hot code upgrades on a larger scale (application and release levels) work
only for systems built according to OTP principles.&lt;/p&gt;
&lt;h2&gt;Hot Code Upgrades: The Basics&lt;/h2&gt;
&lt;p&gt;A good starting point to understand hot code reload is
&lt;a href=&quot;/2018/10/16/elixir-alchemy-hot-code-reloading-in-elixir.html&quot;&gt;Hot Code Reloading in Elixir&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It explains the following key points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to reload code for a single module&lt;/li&gt;
&lt;li&gt;How &lt;strong&gt;two&lt;/strong&gt; versions of code exist after loading a new version of the module: &lt;em&gt;new code&lt;/em&gt; and &lt;em&gt;old code&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The importance of &lt;em&gt;external&lt;/em&gt; calls, which make it possible to transition from old code to new code&lt;/li&gt;
&lt;li&gt;How &lt;code&gt;GenServer&lt;/code&gt; helps us make such a transition seamlessly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, I&amp;#39;d like to highlight one important concept in-depth: code purge.&lt;/p&gt;
&lt;h2&gt;Should You Code Purge in Elixir?&lt;/h2&gt;
&lt;p&gt;What happens if we want to upgrade code two or more times?&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s create a small mix project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix new code_purge
cd code_purge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then update &lt;code&gt;lib/code_purge.ex&lt;/code&gt; to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/code_purge.ex
defmodule CodePurge do
  def pi do
    3.14
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we launch iex shell with mix:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex -S mix
iex(1)&amp;gt; CodePurge.pi
3.14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then update &lt;code&gt;lib/code_purge.ex&lt;/code&gt; to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/code_purge.ex
defmodule CodePurge do
  def pi do
    3.142
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And recompile the project in a &lt;strong&gt;separate shell&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix compile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our iex shell, we reload the module code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(2)&amp;gt; :code.load_file(CodePurge)
{:module, CodePurge}
iex(3)&amp;gt; CodePurge.pi
3.142
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All has worked as expected. &lt;code&gt;:code.load_file/1&lt;/code&gt; found the updated
&lt;code&gt;Elixir.CodePurge.beam&lt;/code&gt; in &lt;code&gt;_build/dev/lib/code_purge/ebin&lt;/code&gt; folder
(as mix sets up code paths for us) and reloaded it.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;But what happens if we try to reload this module once more, without actually changing it?:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(4)&amp;gt; :code.load_file(CodePurge)
{:error, :not_purged}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;What Went Wrong Here?&lt;/h3&gt;
&lt;p&gt;Wow, that doesn&amp;#39;t work. This is because Erlang can&amp;#39;t have two versions of old code.&lt;/p&gt;
&lt;p&gt;To overcome this, there are two other methods of &lt;code&gt;:code&lt;/code&gt;: &lt;code&gt;:code.purge/1&lt;/code&gt; and &lt;code&gt;:code.soft_purge/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;purge&lt;/em&gt; evicts the old code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(5)&amp;gt; :code.purge(CodePurge)
false
iex(6)&amp;gt; :code.load_file(CodePurge)
{:module, CodePurge}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can upgrade the code of the module again after the purge. But why do we even need to control that? Why not purge code automatically?&lt;/p&gt;
&lt;p&gt;Well, there may still be processes running old code, and we should decide what to do with
them during the upgrade. This is also why there are two functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:code.purge/1&lt;/code&gt; — kills processes running old code&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:code.soft_purge/1&lt;/code&gt; — fails if there are any processes running old code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This leads to important consequences: if we want to upgrade our code more than once, our processes will be
killed by default during upgrades.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s illustrate this.&lt;/p&gt;
&lt;h2&gt;How Not to Do a Code Upgrade&lt;/h2&gt;
&lt;p&gt;First, add file &lt;code&gt;lib/code_purge/pi.ex&lt;/code&gt; to your toy project
with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/code_purge/pi.ex
defmodule CodePurge.Pi do
  def start_link do
    spawn_link(&amp;amp;server/0)
  end

  def server do
    receive do
      {:get, from} -&amp;gt;
        send(from, {:ok, 3.14})
        CodePurge.Pi.server()
    end
  end

  def get(pid) do
    send(pid, {:get, self()})

    receive do
      {:ok, value} -&amp;gt;
        {:ok, value}
    after
      1000 -&amp;gt;
        :error
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, run iex shell, spawn a server and check everything is fine:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; pid = CodePurge.Pi.start_link()
#PID&amp;lt;0.140.0&amp;gt;
iex(2)&amp;gt; CodePurge.Pi.get(pid)
{:ok, 3.14}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, reload the module once (without any actual changes to functions) and try to purge it
so that you can do the next &amp;#39;upgrade&amp;#39;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(3)&amp;gt; :code.load_file(CodePurge.Pi)
{:module, CodePurge.Pi}
iex(4)&amp;gt; :code.purge(CodePurge.Pi)
** (EXIT from #PID&amp;lt;0.152.0&amp;gt;) shell process exited with reason: killed
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What Happened Here?&lt;/h2&gt;
&lt;p&gt;As expected, your server just died, and even an external call to &lt;code&gt;CodePurge.Pi.server/0&lt;/code&gt;
couldn&amp;#39;t save you. The server didn&amp;#39;t receive messages
and so didn&amp;#39;t transition to the new code after the first upgrade.&lt;/p&gt;
&lt;p&gt;This isn&amp;#39;t robust. One of the obvious reasons
for the failure is that we didn&amp;#39;t
use OTP libraries (&lt;code&gt;GenServer&lt;/code&gt; and related libraries) dedicated to creating this kind of server.&lt;/p&gt;
&lt;h3&gt;Avoid Spawn in Real-World Software Development&lt;/h3&gt;
&lt;p&gt;In many books and articles, we see code examples demonstrating the power of Elixir or Erlang:
tons of processes easily spawned directly with &lt;code&gt;spawn&lt;/code&gt; or &lt;code&gt;spawn_link&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, in real-world software development, we generally should avoid creating
home-brewed servers or other long-running processes, and should instead use OTP libraries.&lt;/p&gt;
&lt;p&gt;Even for &amp;#39;one-off&amp;#39; asynchronous tasks, we shouldn&amp;#39;t directly use &lt;code&gt;spawn&lt;/code&gt; or &lt;code&gt;spawn_link&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Elixir has a great alternative for &lt;code&gt;spawn&lt;/code&gt;, though: &lt;code&gt;Task&lt;/code&gt; module (covered in depth
in the AppSignal article &lt;a href=&quot;/2017/05/18/elixir-alchemy-demystifying-processes-in-elixir.html&quot;&gt;Demystifying processes in Elixir&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;How To Do a Code Upgrade Using GenServer&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s create a better version of our server in &lt;code&gt;lib/code_purge/pi_gs.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/code_purge/pi_gs.ex
defmodule CodePurge.PiGs do
  use GenServer

  def start_link(value \\ 3.14) do
    GenServer.start_link(__MODULE__, value)
  end

  def init(value) do
    {:ok, value}
  end

  def handle_call(:get, _from, value) do
    {:reply, value, value}
  end

  def get(pid) do
    GenServer.call(pid, :get)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now, try to upgrade/purge the code of a running process several times:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1)&amp;gt; {:ok, pid} = CodePurge.PiGs.start_link()
{:ok, #PID&amp;lt;0.161.0&amp;gt;}
iex(2)&amp;gt; CodePurge.PiGs.get(pid)
3.14
iex(3)&amp;gt; :code.load_file(CodePurge.PiGs)
{:module, CodePurge.PiGs}
iex(4)&amp;gt; :code.purge(CodePurge.PiGs)
false
iex(5)&amp;gt; :code.load_file(CodePurge.PiGs)
{:module, CodePurge.PiGs}
iex(6)&amp;gt; :code.purge(CodePurge.PiGs)
false
iex(7)&amp;gt; CodePurge.PiGs.get(pid)
3.14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing bad happens! The reason why is easy to understand.&lt;/p&gt;
&lt;p&gt;Our &lt;code&gt;pid&lt;/code&gt; process doesn&amp;#39;t spin in &lt;code&gt;CodePurge.PiGs&lt;/code&gt; code.
It runs a &lt;code&gt;GenServer&lt;/code&gt; loop, and we don&amp;#39;t update the &lt;code&gt;GenServer&lt;/code&gt; module code at all.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CodePurge.PiGs&lt;/code&gt; is a &lt;em&gt;callback module&lt;/em&gt;, and the name is kept in a &lt;code&gt;GenServer&lt;/code&gt; internal state.
&lt;code&gt;GenServer&lt;/code&gt; makes external calls to &lt;code&gt;CodePurge.PiGs&lt;/code&gt; functions when serving &lt;code&gt;GenServer&lt;/code&gt; requests.&lt;/p&gt;
&lt;p&gt;The main challenge is to keep updating the states of &lt;code&gt;GenServer&lt;/code&gt; processes, so that any new code can work.&lt;/p&gt;
&lt;p&gt;For a single &lt;code&gt;GenServer&lt;/code&gt;, this can be done through &lt;code&gt;:sys&lt;/code&gt; module and &lt;code&gt;code_change&lt;/code&gt; callback
of &lt;code&gt;GenServer&lt;/code&gt;. This is covered in depth in the previously mentioned
&lt;a href=&quot;/2018/10/16/elixir-alchemy-hot-code-reloading-in-elixir.html&quot;&gt;hot code reloading article&lt;/a&gt;,
here, we&amp;#39;ll only briefly demonstrate it.&lt;/p&gt;
&lt;p&gt;Without closing the previous iex session,
let&amp;#39;s update &lt;code&gt;lib/code_purge/pi_gs.ex&lt;/code&gt; to the following and compile:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/code_purge/pi_gs.ex
defmodule CodePurge.PiGs do
  use GenServer

  def start_link(value \\ 3.14) do
    GenServer.start_link(__MODULE__, value)
  end

  def init(value) do
    {:ok, [value]}
  end

  def handle_call(:get, _from, st) do
    [value] = st
    {:reply, value, st}
  end

  def get(pid) do
    GenServer.call(pid, :get)
  end

  def code_change(_old_vsn, value, _extra) do
    {:ok, [value]}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;code_change&lt;/code&gt; we updated the state, just wrapping it with a list.
We also updated &lt;code&gt;handle_call&lt;/code&gt; and &lt;code&gt;init&lt;/code&gt; callbacks.
Now, in the existing iex session, run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(8)&amp;gt; :code.purge(CodePurge.PiGs)
false
iex(9)&amp;gt; :sys.suspend(pid)
:ok
iex(10)&amp;gt; :code.load_file(CodePurge.PiGs)
{:module, CodePurge.PiGs}
iex(11)&amp;gt; :sys.change_code(pid, CodePurge.PiGs, nil, [])
:ok
iex(12)&amp;gt; :sys.resume(pid)
:ok
iex(13)&amp;gt; CodePurge.PiGs.get(pid)
3.14
iex(14)&amp;gt; :sys.get_state(pid)
[3.14]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything works fine, and the last call to &lt;code&gt;:sys.get_state&lt;/code&gt; demonstrates that the
state has actually changed.&lt;/p&gt;
&lt;h2&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;In the first part of this series, we&amp;#39;ve seen that a &lt;code&gt;GenServer&lt;/code&gt; implementation is needed
for effective hot code upgrades. We&amp;#39;ve also demonstrated how to upgrade a single
&lt;code&gt;GenServer&lt;/code&gt; instance consistently.&lt;/p&gt;
&lt;p&gt;Upgrading an individual process, together with its callback module,
can be used as a &amp;#39;tactical weapon&amp;#39; to fix localized bugs or
add some logging.&lt;/p&gt;
&lt;p&gt;But updating a system at a greater scale, on a regular basis, requires more powerful tools. In the next part of the series, I&amp;#39;ll delve into the world of supervisors in Elixir.&lt;/p&gt;
&lt;p&gt;I hope you found this run-through of hot code reloading useful. See you next time for supervisors!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building Aggregates in Elixir and PostgreSQL</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/07/13/building-aggregates-in-elixir-and-postgresql.html"/>
    <id>https://blog.appsignal.com/2021/07/13/building-aggregates-in-elixir-and-postgresql.html</id>
    <published>2021-07-13T00:00:00+00:00</published>
    <updated>2021-07-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this article, we will describe the roles and implementation of aggregates in Elixir and PostgreSQL.</summary>
    <content type="html">&lt;p&gt;In this article, I will describe the roles and implementation of aggregates
in Elixir and PostgreSQL. We&amp;#39;ll learn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;what domain invariants are&lt;/li&gt;
&lt;li&gt;how to use
aggregates to protect them&lt;/li&gt;
&lt;li&gt;what to pay attention to when choosing a
specific implementation for your aggregates&lt;/li&gt;
&lt;li&gt;why
domain knowledge is essential when designing suitable aggregates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We have a lot of ground to cover, so let&amp;#39;s dive right in!&lt;/p&gt;
&lt;h2&gt;What Are Domain Invariants?&lt;/h2&gt;
&lt;p&gt;Let’s start by looking at a core concept: domain invariants. A &lt;em&gt;domain invariant&lt;/em&gt; is a fact that always has to be true in your business domain.
Here are some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In an e-commerce platform, a cart&amp;#39;s total has to be the sum of all product
prices and applied discounts.&lt;/li&gt;
&lt;li&gt;In a booking application, a room cannot be booked by two different people at
the same time.&lt;/li&gt;
&lt;li&gt;In accounting software, the current account balance has to be the sum of
all the transactions and a withdrawal cannot be made when the balance is below 0.&lt;/li&gt;
&lt;li&gt;With a carpooling app, there can be a max of X people in the car (where X is the
maximum capacity of the car).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Aggregates Protect Invariants&lt;/h2&gt;
&lt;p&gt;Now let&amp;#39;s look at aggregates. &lt;strong&gt;The job of an aggregate is to protect the invariants&lt;/strong&gt; for a given entity or
group of entities.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s continue with the example of the carpooling application. One of our invariants is that
the number of people who sign up for a ride should never exceed the number of
seats:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Ride do
  def book(ride_id, passenger_id, now \\ DateTime.utc_now()) do
    ride = fetch_ride(ride_id)

    if can_add?(ride, passenger_id) do
      passenger = insert_passenger(ride_id, passenger_id)
      {:ok, ride, passenger}
    else
      {:error, :cannot_add}
    end

  end

  defp can_add?(ride, passenger_id) do
    # Any conditions we need to check
    limit_not_exceeded?(ride) &amp;amp;&amp;amp; passenger_not_blocked?(ride, passenger)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we don&amp;#39;t explicitly control concurrency, nothing prevents two different processes from booking the same ride when there&amp;#39;s only one seat left:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-07/incorrect-execution.png&quot; alt=&quot;incorrect execution&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Depending on how we model the data and the updates, we might end up with different results.&lt;/p&gt;
&lt;p&gt;If we insert a participant as a new row, we might end up with more participants.&lt;/p&gt;
&lt;p&gt;If we keep the list of participants as a list on the
&lt;code&gt;Ride&lt;/code&gt;, the participant added by Process B might be overridden by the one added by Process A (which is known as a &lt;a href=&quot;https://www.geeksforgeeks.org/concurrency-problems-in-dbms-transactions/&quot;&gt;Lost Update Problem&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;There is often more than one invariant that we need to protect. Examples from our carpooling app might include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If one user blocks another one, they should not be able to ride in the same car.&lt;/li&gt;
&lt;li&gt;A premium user can choose the front seat if there&amp;#39;s no other premium user already booked.&lt;/li&gt;
&lt;li&gt;For multi-stop rides, you cannot add a new stop if it conflicts with the existing route (according to some business rules).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Editing any of the information related to a ride can endanger any of those invariants. That&amp;#39;s why we need to have a proper boundary to run all the checks and validations.&lt;/p&gt;
&lt;h2&gt;The Aggregate and the Root&lt;/h2&gt;
&lt;p&gt;An aggregate needs to have a required boundary of consistency. Within that boundary, all invariants have to always be true. Every potential update we make to the aggregate should include all the necessary checks.&lt;/p&gt;
&lt;p&gt;Typically, we use the &lt;a href=&quot;https://martinfowler.com/bliki/DDD_Aggregate.html&quot;&gt;aggregate root&lt;/a&gt; to help us do that. The aggregate root is the &amp;quot;main&amp;quot; entity of our aggregate.&lt;/p&gt;
&lt;p&gt;In our example, the &lt;code&gt;Ride&lt;/code&gt; is the aggregate root, while the entire aggregate consists of the &lt;code&gt;Ride&lt;/code&gt; and all &lt;code&gt;Participant&lt;/code&gt;s associated with that ride.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-07/aggregate.png&quot; alt=&quot;aggregate anatomy&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The general rule is that &lt;strong&gt;all updates for any entities in the aggregate should go through the aggregate root and validate the invariants across the entire aggregate&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Every update done to one of the aggregate&amp;#39;s entities has the potential of breaking one of the invariants. A single path for all the updates allows us to verify
all of the changes in a consistent way.&lt;/p&gt;
&lt;h2&gt;How to Implement Aggregates in Elixir&lt;/h2&gt;
&lt;p&gt;Our goal is to make sure that all the invariants are
true after saving an aggregate.&lt;/p&gt;
&lt;p&gt;Since we essentially want to perform proper concurrency control, we need to do the following for every change:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make sure no one else can change the resource until we&amp;#39;re finished.&lt;/li&gt;
&lt;li&gt;Check all the invariants and rules.&lt;/li&gt;
&lt;li&gt;Make all the necessary changes.&lt;/li&gt;
&lt;li&gt;Allow others to use the resource.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#39;s look at some ways of achieving that.&lt;/p&gt;
&lt;h2&gt;The Process-based Approach&lt;/h2&gt;
&lt;p&gt;One of the jobs of an aggregate is to prevent conflicting, concurrent updates. In Elixir, we have a tool for that — a process.&lt;/p&gt;
&lt;p&gt;A process handles incoming messages sequentially. If we can ensure that a single process does all operations on an aggregate, conflicting updates should not be a problem.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll need a way to find a process for each aggregate. &lt;a href=&quot;https://hexdocs.pm/elixir/Registry.html&quot;&gt;Registry&lt;/a&gt; is a nice tool for that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Ride do
  use GenServer

  def start_link([]) do
    GenServer.start_link(__MODULE__, [], name: get_name(ride_id))
  end

  def add_passenger(ride_id, passenger_id) do
    GenServer.call(get_name(ride_id), {:add_passenger, passenger_id})
  end

  def handle_call({:add_passenger, passenger_id}, _from, state) do
    # The calls are processed sequentially

    if can_add?(state, passenger_id) do
      new_state = insert_passenger(state.ride_id, passenger_id)
      {:reply, ok, new_state}
    else
      {:reply, {:error, :no_seats_left}, state}
    end
  end

  defp get_name(ride_id) do
    {:via, Registry, {RideRegistry, {__MODULE__, ride_id}}}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The biggest issue with the process-based approach is that problems start appearing when we run our code on more than one node.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Registry&lt;/code&gt; only runs locally. If two nodes attempt to do operations on the same entity, nothing prevents them from doing so simultaneously.&lt;/p&gt;
&lt;p&gt;Solutions like the &lt;a href=&quot;https://erlang.org/doc/man/global.html&quot;&gt;global registry&lt;/a&gt; won&amp;#39;t really help, either, since they generally favor availability over
consistency. This means that, in the event of node partition (which &lt;em&gt;will&lt;/em&gt; happen, sooner or later), two nodes can end up registering their own processes
for a specific entity, leading to the same problem as the local registry.&lt;/p&gt;
&lt;p&gt;The chances of that happening are lower than with &lt;code&gt;Registry&lt;/code&gt;, but it&amp;#39;s still not a safe solution.&lt;/p&gt;
&lt;h2&gt;The Database Approach&lt;/h2&gt;
&lt;p&gt;We can use a database as a source of truth for our needs. If your database supports locks, you can use that mechanism to prevent concurrent updates.&lt;/p&gt;
&lt;p&gt;The necessary steps for updates are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Fetch the resource you want to modify using the &lt;code&gt;FOR UPDATE&lt;/code&gt; lock.&lt;/li&gt;
&lt;li&gt;Verify all the invariants.&lt;/li&gt;
&lt;li&gt;Make updates.&lt;/li&gt;
&lt;li&gt;Release the lock.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Firstly, we need to lock the resource that we&amp;#39;re trying to modify. Since there can be another process in the middle of another transaction, we need to make sure that we fetch the latest version of the resource — hence the &lt;code&gt;FOR UPDATE&lt;/code&gt; option for the lock.&lt;/p&gt;
&lt;p&gt;This guarantees that if there&amp;#39;s another process which has already locked that resource, our process will wait for its turn and fetch the most recent, already committed version of that resource:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Ride do
  def add_passenger(ride_id, passenger, now \\ DateTime.utc_now()) do
    Repo.transaction(fn -&amp;gt;
      ride =
        Ride
        |&amp;gt; lock(&amp;quot;FOR UPDATE&amp;quot;)
        |&amp;gt; where(id: ^ride_id)
        |&amp;gt; Repo.one()

      if can_add?(ride, passenger_id) do
        passenger = insert_passenger(ride_id, passenger_id)
        {:ok, ride, passenger}
      else
        {:error, :cannot_add}
      end
    end)
  end

  defp can_add?(ride, passenger_id) do
    # Any conditions we need to check
    limit_not_exceeded?(ride) &amp;amp;&amp;amp; passenger_not_blocked?(ride, passenger)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since the locks are automatically released once a transaction is committed, we don&amp;#39;t need to do that explicitly:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-07/pessimistic-lock.png&quot; alt=&quot;pessimistic lock&quot;/&gt;&lt;/p&gt;
&lt;p&gt;This approach is called &lt;strong&gt;pessimistic locking&lt;/strong&gt;. As the name implies, we want to make sure that nobody else is doing another operation even before we start.&lt;/p&gt;
&lt;p&gt;There are some problems with this approach.&lt;/p&gt;
&lt;p&gt;First, no matter what the operation is, we have to wait until a lock is released before doing any other work. This can be a problem if the steps necessary to
perform the business transaction are long.&lt;/p&gt;
&lt;p&gt;If transactions last a long time, and only one can happen at a time, we risk lowering the throughput, increasing the latency, and hurting the user experience.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s another problem with waiting. Since the lock has to happen inside a database transaction, the process must hold to that transaction for the entire
operation. This is a problem because of the limited pool size of database connections. Every process waiting to acquire a lock occupies a connection that could be used for some other query.&lt;/p&gt;
&lt;p&gt;Finally, this approach won&amp;#39;t easily work for business
transactions that span multiple HTTP requests. If the business transaction is more complicated and requires some input from the user, pessimistic locking is
probably not a good choice.&lt;/p&gt;
&lt;p&gt;We can address these problems by using &lt;strong&gt;optimistic locking&lt;/strong&gt; instead.&lt;/p&gt;
&lt;h2&gt;Optimistic Version Control&lt;/h2&gt;
&lt;p&gt;In optimistic locking, you rely on the assumption that no other process will change the aggregate.&lt;/p&gt;
&lt;p&gt;Whether that&amp;#39;s a safe assumption to make depends on the specific use case. For example, the chances of a conflict are different for an e-commerce system, where a user only operates on their own cart, versus a booking application — where multiple people
might want to book a concert ticket at the same time.&lt;/p&gt;
&lt;p&gt;Understanding your domain and specific use case is important!&lt;/p&gt;
&lt;p&gt;The steps for optimistic locking are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You start a transaction and fetch the resource without locking it.&lt;/li&gt;
&lt;li&gt;You verify all the constraints and do all the work without actually committing the changes.&lt;/li&gt;
&lt;li&gt;Just before you commit, you lock the resource and verify if the version hasn&amp;#39;t changed (which would mean that some other process overwrote the resource) and bump the version.&lt;/li&gt;
&lt;li&gt;If the previous step passes, you commit the transaction. If not, you roll back the changes and return an error.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def add_passenger(ride_id, passenger_id) do
  ride = fetch_ride(ride_id)

  Repo.transaction(fn -&amp;gt;
    with true &amp;lt;- can_add?(ride, passenger_id),
      :ok &amp;lt;- insert_passenger(ride, passenger_id),
      :ok &amp;lt;- check_and_update_version(ride, ride.version + 1) do
      :ok
    else
      {:error, :versions_dont_match} -&amp;gt; Repo.rollback(:version_conflict)

      # Other error handling skipped
    end
  end)
end

defp fetch_ride(ride_id) do
  Repo.get(Ride, ride_id) |&amp;gt; Repo.preload(:passengers)
end

def check_and_update_version(ride, new_version) do
  query =
    Ride
    |&amp;gt; where(id: ^ride_id)
    |&amp;gt; where(version: ^ride.version)

  case Repo.update_all(query, set: [version: new_version]) do
    {1, _} -&amp;gt; :ok
    # No record found, so the version must have changed in the meantime
    {0, _} -&amp;gt; {:error, :versions_dont_match}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that we used a single update query here to verify the invariant. This works because Postgres prevents two or more transactions from making
conflicting updates by double-checking the &lt;code&gt;where&lt;/code&gt; clauses. See the &lt;a href=&quot;https://www.postgresql.org/docs/9.5/transaction-iso.html&quot;&gt;&amp;#39;Read
Committed Isolation Level&amp;#39; section from the docs&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2021-07/optimistic-lock.png&quot; alt=&quot;optimistic lock&quot;/&gt;&lt;/p&gt;
&lt;p&gt;With optimistic locking, most of the work is done before we lock the resource.&lt;/p&gt;
&lt;p&gt;In general, there&amp;#39;s no need to use a transaction for the changes. If you can tolerate the state being inconsistent for a bit (which might also be a necessity in a distributed environment), instead of rolling back the transaction, you can use
any other mechanism (like &lt;a href=&quot;https://microservices.io/patterns/data/saga.html&quot;&gt;the saga pattern&lt;/a&gt;)
to roll back the changes manually after detecting a conflict.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s also nothing preventing you from making the business transaction span across multiple requests, giving you more flexibility (the only thing you need to do is pass the initial
version id from request to request or save it somewhere).&lt;/p&gt;
&lt;h2&gt;Optimistic Locking — Alternatives to Version&lt;/h2&gt;
&lt;p&gt;The exact solution you use depends on the specific use case and the business logic behind it. While keeping the &lt;code&gt;version&lt;/code&gt; number is a generic solution that works for every case (and is &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Changeset.html#optimistic_lock/3&quot;&gt;supported by
Ecto!&lt;/a&gt;), you can
make it better by using domain expertise.&lt;/p&gt;
&lt;p&gt;In many cases, detecting a version conflict does not mean that we have to roll
back all the changes. In our example, we might keep a &lt;code&gt;seats_left&lt;/code&gt; field on each
ride. Instead of verifying the version number (and potentially returning an
error for transactions that are correct from a business standpoint), we might
use that field for concurrency control. As long as the number is greater
than 0, we allow the update:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp decrease_seats_left(ride_id) do
  query =
    Ride
    |&amp;gt; where(id: ^ride_id)
    |&amp;gt; where([r], r.seats_left &amp;gt; 0) # Protects our invariant

  case Repo.update_all(query, inc: [seats_left: -1]) do
    {1, _} -&amp;gt; :ok
    {0, _} -&amp;gt; {:error, :no_seats_left}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This helps both the user experience and the performance of the system (since
fewer queries are made).&lt;/p&gt;
&lt;h2&gt;Domain Knowledge is Key&lt;/h2&gt;
&lt;p&gt;Concurrency control might seem like a purely technical problem, but it&amp;#39;s often
not. &lt;strong&gt;Carefully analyzing the domain can lead to a far superior (and simpler)
solution than relying on generic technical patterns.&lt;/strong&gt; It&amp;#39;s useful to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Carefully analyze the domain invariants.&lt;/li&gt;
&lt;li&gt;Make the invariants explicit in the codebase.&lt;/li&gt;
&lt;li&gt;Understand the chances of invariant violations.&lt;/li&gt;
&lt;li&gt;Understand the consequences of invariant violations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;#39;ll realize that the problem is not as black-and-white as we often think. Looking at it from the technical perspective, we see a strictly
correct or incorrect state.&lt;/p&gt;
&lt;p&gt;There will be certain cases where fully
protecting all the invariants will be too hard or even harmful in real life. Plane
overbooking is one example where the invariant is violated (to some
degree) on purpose.&lt;/p&gt;
&lt;p&gt;In these instances, designing processes to detect and deal
with invariant violations might be better than trying to prevent those
violations.&lt;/p&gt;
&lt;h2&gt;Events, CQRS, and Read and Write Models&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;When talking about aggregates, it&amp;#39;s really easy to go down the DDD
rabbit hole&lt;/strong&gt;. You often see aggregates emitting events, or using separate data
models for reads and writes. It&amp;#39;s easy to start thinking about event sourcing.&lt;/p&gt;
&lt;p&gt;Are those techniques useful? Of course!&lt;/p&gt;
&lt;p&gt;The thing is that you don&amp;#39;t have to solve all of them at once. It&amp;#39;s also really
hard to do most of the cases.&lt;/p&gt;
&lt;p&gt;Designing well-isolated, event-sourced aggregates might seem easy on paper or
when starting from scratch.&lt;/p&gt;
&lt;p&gt;Most of the time, though, you&amp;#39;ll be working
on a messy codebase that you want to make better (which is fine!).&lt;/p&gt;
&lt;p&gt;In such a scenario, building a fully event-driven aggregate is really challenging.
Making sure that the events can cover all of the use cases and possible states
is a lot of work.&lt;/p&gt;
&lt;p&gt;But we can still benefit a lot just from making the aggregates a bit more
explicit. Remember: the aggregate&amp;#39;s job is not to emit events or use a write
model, it&amp;#39;s to protect domain invariants.&lt;/p&gt;
&lt;p&gt;One of the best first steps you can do when refactoring an existing codebase is
to find those invariants, put them in the code, and validate them in an explicit
way.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;In this article, we&amp;#39;ve learned that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A domain invariant always has to be true in a particular domain.&lt;/li&gt;
&lt;li&gt;Concurrent updates can lead to compromised invariants and Lost Update problems.&lt;/li&gt;
&lt;li&gt;Elixir processes can be used for concurrency control, but it&amp;#39;s hard to do so with more than one node.&lt;/li&gt;
&lt;li&gt;Locking a resource before using it is called &amp;#39;pessimistic concurrency control&amp;#39;.&lt;/li&gt;
&lt;li&gt;&amp;#39;Optimistic concurrency control&amp;#39; is when we assume that it&amp;#39;s safe to do an operation but
still verify this just before committing changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Maybe most importantly, we&amp;#39;ve seen that domain knowledge is essential and that
it&amp;#39;s crucial to take small steps in the right direction instead of
trying to do everything right the first time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Test WebSocket Clients in Elixir with a Mock Server</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/06/22/how-to-test-websocket-clients-in-elixir-with-a-mock-server.html"/>
    <id>https://blog.appsignal.com/2021/06/22/how-to-test-websocket-clients-in-elixir-with-a-mock-server.html</id>
    <published>2021-06-22T00:00:00+00:00</published>
    <updated>2021-06-22T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how to implement a long-running connection between two services with WebSocket, and then write unit tests for functionality.</summary>
    <content type="html">&lt;p&gt;In this post, we&amp;#39;ll give a very high-level overview of how to implement a long-running connection between two services with WebSocket, and then we&amp;#39;ll write unit tests for functionality.&lt;/p&gt;
&lt;p&gt;The WebSocket protocol allows two-way communication between two channels.
Most developers know it as a fast, near real-time communication medium between a client and a server.&lt;/p&gt;
&lt;p&gt;In the Phoenix and Elixir world, many recognize Websockets from abstractions built on top of it, like LiveView or Channels.&lt;/p&gt;
&lt;p&gt;But WebSocket is also a great communication medium for an app built on microservices architecture.
Let&amp;#39;s say we have an e-commerce application that uses (among others), two services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Orders&lt;/code&gt; — Create and manage the user&amp;#39;s orders&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Payments&lt;/code&gt; — Process the payments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a user makes a purchase, the &lt;code&gt;Orders&lt;/code&gt; service creates an order corresponding to the purchase and sends it to the &lt;code&gt;Payments&lt;/code&gt; service.
This service can then respond with a payment page URL that the user needs to visit to complete his payment.
After completion, the &lt;code&gt;Orders&lt;/code&gt; service needs to create an invoice for the order and send it to the user, so it will need a way to watch for the completion of payments.&lt;/p&gt;
&lt;p&gt;For such an architecture, a long-running connection between &lt;code&gt;Orders&lt;/code&gt; and &lt;code&gt;Payments&lt;/code&gt; through a WebSocket is a great choice, as both services can interchange messages and notify the other service about updates or events.&lt;/p&gt;
&lt;h2&gt;Setting Up a WebSocket Client&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/websockex/readme.html&quot;&gt;WebSockex&lt;/a&gt; is a library for implementing a WebSocket client in Elixir. &lt;a href=&quot;https://gist.github.com/pulkit110/b8fe73fe7db7f424bcb3a88f89806ff7#file-payments_client-ex&quot;&gt;Here&amp;#39;s a very simplified implementation of how the client could look on the &lt;code&gt;Orders&lt;/code&gt; service&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The client behaves as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It is started as a process with a URL of the &lt;code&gt;Payments&lt;/code&gt; WebSocket Server and some details about the &lt;code&gt;order&lt;/code&gt; it needs to process.&lt;/li&gt;
&lt;li&gt;As soon as it&amp;#39;s connected, it sends a message to the &lt;code&gt;Payments&lt;/code&gt; service to initiate the payment process.&lt;/li&gt;
&lt;li&gt;At some point (normally soon after the payment has been initialized), the &lt;code&gt;Payments&lt;/code&gt; service responds with a list of available payment methods for the order.&lt;/li&gt;
&lt;li&gt;The client selects the first payment method and asks &lt;code&gt;Payments&lt;/code&gt; to initiate payment with that method.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Payments&lt;/code&gt; sends a message with the payment page url that the &lt;code&gt;Orders&lt;/code&gt; service can use to initiate a payment on the web app.&lt;/li&gt;
&lt;li&gt;At some point, &lt;code&gt;Payments&lt;/code&gt; sends a message to the client informing them about the state of the transaction, e.g. &lt;code&gt;FULFILL&lt;/code&gt;, &lt;code&gt;CANCEL&lt;/code&gt; etc.&lt;/li&gt;
&lt;li&gt;If the payment state is &lt;code&gt;FULFILL&lt;/code&gt;, then fulfill the order. If the payment state is &lt;code&gt;CANCEL&lt;/code&gt;, then cancel the order and close the connection.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Testing External Services&lt;/h2&gt;
&lt;p&gt;Now that we have a working WebSocket client in place, the next question is: how do we test it? It connects to an external service (this service is ultimately controlled by us, but is still external in terms of the &lt;code&gt;Orders&lt;/code&gt; service).&lt;/p&gt;
&lt;p&gt;There are several ways to write tests that interact with external services:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a separate service for the API Client and stub out those requests with &lt;a href=&quot;https://github.com/dashbitco/mox&quot;&gt;Mox&lt;/a&gt; from José Valim.&lt;/li&gt;
&lt;li&gt;Mock out the requests during the tests with a library like &lt;a href=&quot;https://github.com/jjh42/mock&quot;&gt;Mock&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Roll out your own web server to handle the requests.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All these methods and their pros and cons have been covered in detail in several posts in the community.
One that I particularly like and recommend is &lt;a href=&quot;https://medium.com/flatiron-labs/rolling-your-own-mock-server-for-testing-in-elixir-2cdb5ccdd1a0&quot;&gt;Testing External Web Requests in Elixir? Roll Your Own Mock Server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll discuss how to write tests for the above client by rolling out our own server during the tests.&lt;/p&gt;
&lt;h2&gt;Creating a Mock Server&lt;/h2&gt;
&lt;p&gt;First, we need to create a mock server that will provide a connection to, and interact with the client.&lt;/p&gt;
&lt;p&gt;We will use &lt;a href=&quot;https://github.com/elixir-plug/plug_cowboy&quot;&gt;plug and cowboy&lt;/a&gt; to create the server and control the socket.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Set Up a Mock HTTP Server&lt;/h3&gt;
&lt;p&gt;Since we might need several of these servers running in parallel during the tests, we&amp;#39;ll need a way to generate ports so that the servers don&amp;#39;t collide.&lt;/p&gt;
&lt;p&gt;We can do this by starting an &lt;code&gt;Agent&lt;/code&gt; that begins randomly at a port and then assigns us a port incrementally during the tests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp get_port do
  unless Process.whereis(__MODULE__), do: start_ports_agent()

  Agent.get_and_update(__MODULE__, fn port -&amp;gt; {port, port + 1} end)
end

defp start_ports_agent do
  Agent.start(fn -&amp;gt; Enum.random(50_000..63_000) end, name: __MODULE__)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The mock server now needs to obtain a port and start listening on that port for connections.&lt;/p&gt;
&lt;p&gt;On each new client connection, we will open a socket (more on this later).
This is the server-side socket that is linked with the client-side socket opened from our WebSocket client implementation.&lt;/p&gt;
&lt;p&gt;This socket is running in its own process, so we&amp;#39;ll need to obtain its PID inside the tests for our test code to be able to interact with it.&lt;/p&gt;
&lt;p&gt;Since the tests only know about the HTTP server and not the socket, we&amp;#39;ll send the socket PID back to the server so we can retrieve it from the test code.
&lt;a href=&quot;https://gist.github.com/pulkit110/b8fe73fe7db7f424bcb3a88f89806ff7#file-mock_websocket_server-ex&quot;&gt;This is how the mock server code looks&lt;/a&gt; (I know it&amp;#39;s a bit complex, but don&amp;#39;t be alarmed — it&amp;#39;ll be easy to understand once we see the socket).&lt;/p&gt;
&lt;p&gt;Using the above server is very simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Start the server:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:ok, {server_ref, url}} = Commerce.Orders.MockWebsocketServer.start(self())
on_exit(fn -&amp;gt; Commerce.Orders.MockWebsocketServer.shutdown(server_ref) end)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect the client, using the above url.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you need to send messages to the client, first obtain the server pid:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;server_pid = Commerce.Orders.MockWebsocketServer.receive_socket_pid()
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Send messages to the server that will be relayed to the client. Check &lt;code&gt;Commerce.Orders.TestSocket.websocket_info/2&lt;/code&gt; for all possible clauses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;send(server_pid, {:send, {:text, frame}})
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This server also sends all the messages that it receives to the owner process. This means that to verify that the server has received a message, you can use:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;assert_receive on the owner:
assert_receive(&amp;quot;SOME MESSAGE&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Set Up the Mock Socket&lt;/h3&gt;
&lt;p&gt;After creating the mock server, you then create the actual server-side socket that will handle the connections. This is the &lt;code&gt;Commerce.Orders.TestSocket&lt;/code&gt; our mock HTTP server dispatches the initial connection to.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gist.github.com/pulkit110/b8fe73fe7db7f424bcb3a88f89806ff7#file-test_socket-ex&quot;&gt;The full code for the test socket can be found here&lt;/a&gt;. Let&amp;#39;s break it down.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;init&lt;/code&gt; is what is called after &lt;code&gt;MockWebsocketServer&lt;/code&gt; starts and it receives a new connection request from our WebSocket client (that we want to test). You can check out the full &lt;a href=&quot;https://ninenines.eu/docs/en/cowboy/2.5/manual/cowboy_websocket/&quot;&gt;&lt;code&gt;cowboy_websocket&lt;/code&gt; documentation&lt;/a&gt; for more details on the supported responses. &lt;code&gt;[{test_pid, agent_pid}]&lt;/code&gt; is the initial state that we sent out from the &lt;code&gt;MockWebsocketServer.dispatch&lt;/code&gt; and we will keep track of that in state to manage sending frames to the socket.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;websocket_init&lt;/code&gt; is called once the connection is upgraded to WebSocket. This is where we send the server socket&amp;#39;s &lt;code&gt;pid&lt;/code&gt; to the &lt;code&gt;MockWebsocketServer&lt;/code&gt;, which the test code can then retrieve using &lt;code&gt;receive_socket_pid&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;websocket_handle&lt;/code&gt; is called for every frame received. This is where we further process the received frame to verify messages from our client. If this differs between different WebSocket clients that we want to test, you could skip the call to &lt;code&gt;handle_websocket_message&lt;/code&gt; and its implementations — just use &lt;code&gt;send(state.pid, to_string(msg))&lt;/code&gt; to send all messages to the test process.
The test process can then verify the frames as required.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;websocket_info&lt;/code&gt; is called for every Erlang message that the process receives. This is what we use to receive messages from the test code, to trigger certain events from the server socket.&lt;/p&gt;
&lt;p&gt;The first argument to this function could be anything that the test code sends, so you can add as many clauses as you want to support to simulate certain events.&lt;/p&gt;
&lt;p&gt;Here, we are only interested in initiating a &lt;code&gt;close&lt;/code&gt; from the test code or sending a particular frame to the client socket.&lt;/p&gt;
&lt;h2&gt;Test Code&lt;/h2&gt;
&lt;p&gt;Now that we have the WebSocket client, mock server and mock socket out of the way, we can get to the actual test code that will test the WebSocket client using the mocks.&lt;/p&gt;
&lt;p&gt;To start the server in our tests, we will use &lt;code&gt;MockWebsocketServer.start&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;setup do
  {:ok, {server_ref, url}} = MockWebsocketServer.start(self())
  on_exit(fn -&amp;gt; MockWebsocketServer.shutdown(server_ref) end)

  %{url: url, server_ref: server_ref}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s test out our client with the mock server in place.&lt;/p&gt;
&lt;p&gt;Instead of writing several smaller tests that test a single part of the client, I am providing a big test case that describes the full interaction. This is so I can describe all available testing options without too much boilerplate code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;interacts with the server&amp;quot;, %{url: url, order: order} do
  {:ok, pid} = WebSocketClient.start_link(%{url: url})
  server_pid = MockWebsocketServer.receive_socket_pid()

  # A payment is initiated immediately after a connection
  assert_receive Jason.encode!(%{initiate_payment: true})

  # WebSocket client receives the payment methods from the server (from the hard coded message response). We do not need any code for this since we generalized it directly in the socket.

  # The payment is initiated with credit card
  assert_receive Jason.encode!(%{initiate_payment: &amp;quot;credit_card&amp;quot;})

  # Send a FULFILL state from the server. This is the alternative to hard coded messages in the server side socket.
  send(server_pid, {:send, {:text, Jason.encode!(%{state: &amp;quot;FULFILL&amp;quot;})}})

  # Confirm that the order was fulfilled
  assert {:ok, %Order{state: &amp;quot;FULFILL&amp;quot;}} = Orders.get_order(order.id)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While it takes some work to set up our mock server and socket to test our WebSocket clients, it makes our testing really smooth and simple. Later, if we add another WebSocket client, we can utilize the same server to unit test the new client without any complex setup or mocking.&lt;/p&gt;
&lt;p&gt;In addition to this, we now have tests that do not depend on any of the client&amp;#39;s implementation details. We are just testing business logic rather than implementation or tying our test code to specific libraries being used in the implementation.&lt;/p&gt;
&lt;p&gt;So if you were to replace the WebSocket client implementation to use &lt;a href=&quot;https://github.com/ninenines/gun&quot;&gt;&lt;code&gt;gun&lt;/code&gt;&lt;/a&gt; instead of &lt;code&gt;WebSockex&lt;/code&gt;, we wouldn&amp;#39;t need to change anything in our tests. In fact, our tests would serve as an additional validation point for this migration, to ensure that everything keeps working as it did before.&lt;/p&gt;
&lt;h2&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;In the post, we briefly touched on a sample microservices architecture, looked at how we could use WebSockets to communicate between different services and saw a very simplified implementation of a WebSocket client using &lt;code&gt;WebSockex&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you are looking for a more complex &lt;code&gt;WebSockex&lt;/code&gt; client example, &lt;a href=&quot;https://sapandiwakar.in/stomp-over-a-websocket-client-in-elixir/&quot;&gt;this post walks through building a complete STOMP client with WebSocket&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How Absinthe Uses Compilation Callbacks for Schema Validation in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2021/01/19/how-absinthe-uses-compilation-callbacks-for-schema-validation-in-elixir.html"/>
    <id>https://blog.appsignal.com/2021/01/19/how-absinthe-uses-compilation-callbacks-for-schema-validation-in-elixir.html</id>
    <published>2021-01-19T00:00:00+00:00</published>
    <updated>2021-01-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Absinthe manages to do a lot of interesting things during its compilation process, let&#039;s take a closer look at it.</summary>
    <content type="html">&lt;p&gt;Absinthe manages to do a lot of interesting things during its compilation process, and today we&amp;#39;re
going to look a bit at how that works. We&amp;#39;ll look closely at how it uses some
metaprograming tricks and module attributes to provide compile-time schema validation for us.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s pretty amazing (to me, at least) that when we use Absinthe, we can have a really simple,
easy-to-use API to define our schema and we &lt;em&gt;still&lt;/em&gt; get a good amount of compile-time type
checking out of it! For example, if we try and use a type that hasn&amp;#39;t yet been defined, we&amp;#39;ll see
an error like this in our terminal when we try and compile our application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;== Compilation error in file lib/blog_web/schema.ex ==
** (Absinthe.Schema.Error) Invalid schema:
/home/devon/sandbox/absinthe_tutorial/lib/blog_web/schema/account_types.ex:10: User_state :custom_enum is not defined in your schema.

  Types must exist if referenced.


    (absinthe 1.4.16) lib/absinthe/schema.ex:271: Absinthe.Schema.__after_compile__/2
    (stdlib 3.13.2) lists.erl:1267: :lists.foldl/3
    (stdlib 3.13.2) erl_eval.erl:680: :erl_eval.do_apply/6
    (elixir 1.11.2) lib/kernel/parallel_compiler.ex:314: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fact that this happens is cool on its own, but &lt;em&gt;how&lt;/em&gt; they manage to do this is what I
think is &lt;strong&gt;really&lt;/strong&gt; cool. It takes a lot of really tricky (but interesting) usage of modules and
module attributes to make it work, and that&amp;#39;s what we&amp;#39;ll be covering today. But before we can get
to the actual type checking, we need to take a quick look at how one defines a schema with
Absinthe, and then how that schema is compiled to create those modules and module attributes using
Elixir compilation callbacks.&lt;/p&gt;
&lt;h2&gt;Defining a Schema with Absinthe&lt;/h2&gt;
&lt;p&gt;To define our GraphQL schema using Absinthe, we need to write a single module in which that schema
is declared, and in that module we need to &lt;code&gt;use Absinthe.Schema&lt;/code&gt;. If your schema is small enough
then doing that in one file is easy enough:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BlogWeb.Schema do
  use Absinthe.Schema

  alias BlogWeb.Resolvers

  object :user do
    field :id, :id
    field :name, :string
    field :posts, list_of(:post) do
      resolve &amp;amp;Resolvers.Content.list_posts/3
    end
  end

  object :post do
    field :id, non_null(:id)
    field :title, non_null(:string)
    field :body, non_null(:string)
    field :user, non_null(:user)
  end

  input_object :post_params do
    field :id, non_null(:id)
    field :title, non_null(:string)
    field :body, non_null(:string)
    field :user_id, non_null(:id)
  end

  query do
    field :posts, list_of(:post) do
      resolve(&amp;amp;Resolvers.Content.list_posts/3)
    end
  end

  mutation do
    field :create_post, :post do
      arg(:params, non_null(:post_params))
      resolve(&amp;amp;Resolvers.Content.create_post/3)
    end

    field :update_post, :post do
      arg(:params, non_null(:post_params))
      resolve(&amp;amp;Resolvers.Content.update_post/3)
    end

    field :delete_post, :post do
      arg(:id, non_null(:id))
      resolve(&amp;amp;Resolvers.Content.delete_post/3)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, once you start building out your application and things get bigger, you generally end up
breaking the schema up into multiple &amp;quot;schema fragment&amp;quot; files and importing the types defined in
those fragments into your schema using the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#import_types/2&quot;&gt;&lt;code&gt;Absinthe.Schema.Notation.import_types/2&lt;/code&gt;&lt;/a&gt;
and the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Schema.Notation.html#import_fields/2&quot;&gt;&lt;code&gt;Absinthe.Schema.Notation.import_fields/2&lt;/code&gt;&lt;/a&gt;
macros.&lt;/p&gt;
&lt;p&gt;To do that with our schema above we might end up doing something like what is below, with each set
of types defined in its own module, each of which calls &lt;code&gt;use Absinthe.Schema.Notation&lt;/code&gt;.
We can imagine that each module is defined in its own file, although they technically don&amp;#39;t need
to be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule BlogWeb.Schema.UserTypes do
  use Absinthe.Schema.Notation

  alias BlogWeb.Resolvers

  object :user do
    field :id, :id
    field :name, :string
    field :posts, list_of(:post) do
      resolve &amp;amp;Resolvers.Content.list_posts/3
    end
  end
end

defmodule BlogWeb.Schema.PostTypes do
  use Absinthe.Schema.Notation

  alias BlogWeb.Resolvers

  object :post do
    field :id, non_null(:id)
    field :title, non_null(:string)
    field :body, non_null(:string)
    field :user, non_null(:user)
  end

  input_object :post_params do
    field :id, non_null(:id)
    field :title, non_null(:string)
    field :body, non_null(:string)
    field :user_id, non_null(:id)
  end

  object :post_queries do
    field :posts, list_of(:post) do
      resolve(&amp;amp;Resolvers.Content.list_posts/3)
    end
  end

  object :post_mutations do
    field :create_post, :post do
      arg(:params, non_null(:post_params))
      resolve(&amp;amp;Resolvers.Content.create_post/3)
    end

    field :update_post, :post do
      arg(:params, non_null(:post_params))
      resolve(&amp;amp;Resolvers.Content.update_post/3)
    end

    field :delete_post, :post do
      arg(:id, non_null(:id))
      resolve(&amp;amp;Resolvers.Content.delete_post/3)
    end
  end
end

defmodule BlogWeb.Schema do
  use Absinthe.Schema

  import_types(Absinthe.Type.Custom)
  import_types(BlogWeb.Schema.UserTypes)
  import_types(BlogWeb.Schema.PostTypes)

  alias BlogWeb.Resolvers

  query do
    import_fields(:post_queries)
  end

  mutation do
    import_fields(:post_mutations)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;But how does Absinthe know that when we&amp;#39;re referencing the &lt;code&gt;:post&lt;/code&gt; type in the definition of our
&lt;code&gt;:user&lt;/code&gt; type, the &lt;code&gt;:post&lt;/code&gt; is a valid type to use? Well, that&amp;#39;s where the fun stuff come in!&lt;/p&gt;
&lt;h2&gt;How Elixir&amp;#39;s Compilation Callbacks Work&lt;/h2&gt;
&lt;p&gt;Well, to know how Absinthe works its magic, first we need to know a bit about Elixir&amp;#39;s compilation
callbacks. A compilation callback is, as it sounds, a function that is executed either before,
during, or after compilation takes place. There are a three compilation callbacks, but the two we
care about for today are the
&lt;a href=&quot;https://hexdocs.pm/elixir/Module.html#module-before_compile-1&quot;&gt;&lt;code&gt;@before_compile&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://hexdocs.pm/elixir/Module.html#module-after_compile-1&quot;&gt;&lt;code&gt;@after_compile&lt;/code&gt;&lt;/a&gt; callbacks.&lt;/p&gt;
&lt;p&gt;These are two functions that are called, as you would assume, &lt;em&gt;before&lt;/em&gt; and &lt;em&gt;after&lt;/em&gt; compilation of
a module. The &lt;code&gt;before_compile&lt;/code&gt; callback receives as an argument the compilation &lt;code&gt;__ENV__&lt;/code&gt;, which
is a struct containing information about the compilation process. More info on what exactly is in
there can be found in &lt;a href=&quot;https://hexdocs.pm/elixir/Macro.Env.html#t:t/0&quot;&gt;the docs for &lt;code&gt;Macro.Env&lt;/code&gt;&lt;/a&gt;.
Likewise, the &lt;code&gt;after_compile&lt;/code&gt; callback receives that same compilation &lt;code&gt;__ENV__&lt;/code&gt;, and also the
compiled bytecode for the module.&lt;/p&gt;
&lt;p&gt;These two callbacks give us the opportunity to set up some things that might be needed for
compilation in our &lt;code&gt;before_compile&lt;/code&gt; callback, and then some checking of things that have just been
compiled in our &lt;code&gt;after_compile&lt;/code&gt; callback. That&amp;#39;s exactly how Absinthe uses those two features
for its schema compilation and schema validation.&lt;/p&gt;
&lt;h2&gt;How Absinthe Does Schema Validation at Compile Time&lt;/h2&gt;
&lt;p&gt;So, what exactly is Absinthe doing when it compiles? Well, let&amp;#39;s start with the compilation of
those schema fragments. &lt;code&gt;Absinthe.Schema.Notation&lt;/code&gt; contains a definition of a &lt;a href=&quot;https://github.com/absinthe-graphql/absinthe/blob/1a03ef223c485f6bcd70d288a71287ab6b32595f/lib/absinthe/schema/notation.ex#L1697&quot;&gt;&lt;code&gt;__before_compile__/1&lt;/code&gt; function&lt;/a&gt;
which is used as the handler for the &lt;code&gt;@before_compile&lt;/code&gt; callback for each of those schema
fragments.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro __before_compile__(env) do
  module_attribute_descs =
    env.module
    |&amp;gt; Module.get_attribute(:absinthe_desc)
    |&amp;gt; Map.new()

  attrs =
    env.module
    |&amp;gt; Module.get_attribute(:absinthe_blueprint)
    |&amp;gt; List.insert_at(0, :close)
    |&amp;gt; reverse_with_descs(module_attribute_descs)

  imports =
    (Module.get_attribute(env.module, :__absinthe_type_imports__) || [])
    |&amp;gt; Enum.uniq()
    |&amp;gt; Enum.map(fn
      module when is_atom(module) -&amp;gt; {module, []}
      other -&amp;gt; other
    end)

  schema_def = %Schema.SchemaDefinition{
    imports: imports,
    module: env.module,
    __reference__: %{
      location: %{file: env.file, line: 0}
    }
  }

  blueprint =
    attrs
    |&amp;gt; List.insert_at(1, schema_def)
    |&amp;gt; Absinthe.Blueprint.Schema.build()

  [schema] = blueprint.schema_definitions

  {schema, functions} = lift_functions(schema, env.module)

  sdl_definitions =
    (Module.get_attribute(env.module, :__absinthe_sdl_definitions__) || [])
    |&amp;gt; List.flatten()
    |&amp;gt; Enum.map(fn definition -&amp;gt;
      Absinthe.Blueprint.prewalk(definition, fn
        %{module: _} = node -&amp;gt;
          %{node | module: env.module}

        node -&amp;gt;
          node
      end)
    end)

  {sdl_directive_definitions, sdl_type_definitions} =
    Enum.split_with(sdl_definitions, fn
      %Absinthe.Blueprint.Schema.DirectiveDefinition{} -&amp;gt;
        true

      _ -&amp;gt;
        false
    end)

  schema =
    schema
    |&amp;gt; Map.update!(:type_definitions, &amp;amp;(sdl_type_definitions ++ &amp;amp;1))
    |&amp;gt; Map.update!(:directive_definitions, &amp;amp;(sdl_directive_definitions ++ &amp;amp;1))

  blueprint = %{blueprint | schema_definitions: [schema]}

  quote do
    unquote(__MODULE__).noop(@desc)

    def __absinthe_blueprint__ do
      unquote(Macro.escape(blueprint, unquote: true))
    end

    unquote_splicing(functions)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At first the code in that function might be tricky to understand, but the most important part of
understanding what&amp;#39;s going on there is looking at the definition of the &lt;code&gt;__absinthe_blueprint__/0&lt;/code&gt;
function. We can see that we&amp;#39;re defining a function that returns a map, and that map contains a
lot of information about the state of things &lt;em&gt;before&lt;/em&gt; the current schema fragment was compiled.
This &lt;code&gt;__absinthe_blueprint__/0&lt;/code&gt; function will be really important in the final compilation step
that we&amp;#39;ll look at in a bit.&lt;/p&gt;
&lt;p&gt;One other really intersting thing about this code this is important to notice is how many calls to
&lt;code&gt;Module.get_attribute/2&lt;/code&gt; there are! This is one of the things that Absinthe leans on heavily for
this compilation process - the use of modules and module attributes as essentially defining global
variables that can be accessed by other modules during &lt;em&gt;their&lt;/em&gt; compilation! There are a lot of
calls to &lt;code&gt;Module.get_attribute/2&lt;/code&gt; and &lt;code&gt;Module.put_attribute/3&lt;/code&gt; in this module, and recognizing
this pattern helps us put the rest of the process into context.&lt;/p&gt;
&lt;p&gt;The other thing happening here is that we&amp;#39;re defining a lot of functions in a dynamically named
module! These functions contain yet more information, and we can see a bit more of how this is
used in the &lt;a href=&quot;https://github.com/absinthe-graphql/absinthe/blob/1a03ef223c485f6bcd70d288a71287ab6b32595f/lib/absinthe/schema.ex#L297&quot;&gt;&lt;code&gt;__before_compile__/1&lt;/code&gt; function defined in &lt;code&gt;Absinthe.Schema&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmacro __before_compile__(_) do
  quote do
    @doc false
    def __absinthe_pipeline_modifiers__ do
      [@schema_provider] ++ @pipeline_modifier
    end

    def __absinthe_schema_provider__ do
      @schema_provider
    end

    def __absinthe_type__(name) do
      @schema_provider.__absinthe_type__(__MODULE__, name)
    end

    def __absinthe_directive__(name) do
      @schema_provider.__absinthe_directive__(__MODULE__, name)
    end

    def __absinthe_types__() do
      @schema_provider.__absinthe_types__(__MODULE__)
    end

    def __absinthe_types__(group) do
      @schema_provider.__absinthe_types__(__MODULE__, group)
    end

    def __absinthe_directives__() do
      @schema_provider.__absinthe_directives__(__MODULE__)
    end

    def __absinthe_interface_implementors__() do
      @schema_provider.__absinthe_interface_implementors__(__MODULE__)
    end

    def __absinthe_prototype_schema__() do
      @prototype_schema
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When each schema fragment is defined, it also defines a module that contains the information about
the module that was just defined - so for example, for our &lt;code&gt;BlogWeb.Schema.UserTypes&lt;/code&gt; module that
we used above, it will define a &lt;code&gt;BlogWeb.Schema.UserTypes.Compiled&lt;/code&gt; module. With this convention,
it allows Absinthe know where to look for information for each module that was compiled with some
schema information.&lt;/p&gt;
&lt;p&gt;And now that all that work has been done during the compilation process, we can look at the
&lt;a href=&quot;https://github.com/absinthe-graphql/absinthe/blob/1a03ef223c485f6bcd70d288a71287ab6b32595f/lib/absinthe/schema.ex#L349&quot;&gt;&lt;code&gt;__after_compile__/2&lt;/code&gt; callback defined in &lt;code&gt;Absinthe.Schema&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def __after_compile__(env, _) do
  prototype_schema =
    env.module
    |&amp;gt; Module.get_attribute(:prototype_schema)

  pipeline =
    env.module
    |&amp;gt; Absinthe.Pipeline.for_schema(prototype_schema: prototype_schema)
    |&amp;gt; apply_modifiers(env.module)

  env.module.__absinthe_blueprint__
  |&amp;gt; Absinthe.Pipeline.run(pipeline)
  |&amp;gt; case do
    {:ok, _, _} -&amp;gt;
      []

    {:error, errors, _} -&amp;gt;
      raise Absinthe.Schema.Error, phase_errors: List.wrap(errors)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is where all that information and all that metaprogramming is actually used for some helpful
user features! In short, that callback will use all of the information that&amp;#39;s been stored in
various module attributes and exposed by defining all of those different functions in all of those
&lt;code&gt;.Compiled&lt;/code&gt; modules to build up something that Absinthe calls a &lt;strong&gt;blueprint&lt;/strong&gt;. This blueprint is
again what it sounds like - it contains the information for how documents will later by evaluated
against the current GraphQL schema during resolution. It then evaluates this blueprint, and if
there are any errors returned from that evaluation they&amp;#39;re raised at the end of the compilation
process!&lt;/p&gt;
&lt;p&gt;Clearly this is kind of a compilcated process, but it&amp;#39;s also a cool way to use some of the basic
features of the Elixir compiler to deliver value to users. Exploring this process helped me learn
a lot about this method of compilation of applications, but it also made it clear to me that the
Absinthe team has put a great deal of time and effort into making this user experience really
great, and for that I&amp;#39;m very thankful!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Top 5 Elixir Blog Posts in 2020 from AppSignal</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/12/16/top-5-elixir-posts-in-2020-from-appsignal.html"/>
    <id>https://blog.appsignal.com/2020/12/16/top-5-elixir-posts-in-2020-from-appsignal.html</id>
    <published>2020-12-16T00:00:00+00:00</published>
    <updated>2020-12-16T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Check out the most appreciated Elixir posts on our blog in 2020.</summary>
    <content type="html">&lt;p&gt;2020 is a year we&amp;#39;re all looking forward to leave behind. But let&amp;#39;s think a bit about nice things like sharing knowledge, even in a year like this.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the list of the top 5 Elixir posts that received the most attention from you. If you need a warm-up: you can &lt;a href=&quot;https://www.youtube.com/watch?v=cCqEyJc-wdk&quot;&gt;play these tunes in the background&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Top 5 Elixir Blog Posts in 2020 ⚗️&lt;/h2&gt;
&lt;h3&gt;&lt;a href=&quot;/2020/03/24/how-to-use-grpc-in-elixir.html&quot;&gt;How to Use gRPC in Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Learn what gRPC is, when you should reach for such a tool, and some of the pros and cons of using it. After going over an introduction of gRPC, we’ll dive right into a sample application where we’ll build an Elixir backend API powered by gRPC.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;/2020/05/19/using-mnesia-in-an-elixir-application.html&quot;&gt;Using Mnesia in an Elixir Application&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Discover more about Mnesia, see when you would use such a tool, and take a look at some of the pros and cons of using it. After covering the fundamentals of Mnesia, we’ll dive right into a sample application where we’ll build an Elixir application that uses Mnesia as its database.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;/2020/07/28/the-state-of-elixir-http-clients.html&quot;&gt;The State of Elixir HTTP Clients&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this post, we’ll look at two Elixir HTTP client libraries: Mint and Finch. We’ll also talk about some of the existing HTTP client libraries in the ecosystem and discuss some of the things that make Mint and Finch different.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;&lt;a href=&quot;/2020/06/24/best-practices-for-background-jobs-in-elixir.html&quot;&gt;Best Practices for Background Jobs in Elixir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you’ve ever deployed a new task, only to find out that it has gone rogue with a bug that caused it to misbehave (e.g.: sending way too many emails, way too quickly), this post is for you.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;/2020/01/29/how-to-get-your-elixir-application-ready-for-ci-cd.html&quot;&gt;How to Get Your Elixir Application Ready for CI/CD&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For this post, we’ll go over what continuous integration and continuous delivery are, the benefits that come along with employing CI/CD, and some best practices that you should follow. We’ll also explore a wide array of Elixir ecosystem tools that can help you create top-notch CI pipelines.&lt;/p&gt;
&lt;h2&gt;Holiday Season is Approaching 🎊🎉🎄❄️&lt;/h2&gt;
&lt;p&gt;That was all for this roundup of favorite articles of 2020! The whole AppSignal team wishes you all the best for the coming year, with little errors and many amazing insights ☃️&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. Don&amp;#39;t forget to subscribe to our &lt;a href=&quot;/elixir-alchemy&quot;&gt;Elixir Alchemy&lt;/a&gt; newsletter!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Understanding Associations in Elixir&#039;s Ecto</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/11/10/understanding-associations-in-elixir-ecto.html"/>
    <id>https://blog.appsignal.com/2020/11/10/understanding-associations-in-elixir-ecto.html</id>
    <published>2020-11-10T00:00:00+00:00</published>
    <updated>2020-11-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Data modeling in Ecto takes a bit of getting used to. The goal of this post is to give a short but definitive answer to this problem.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This post was updated on 9 August 2023 with a code walkthrough for a sample app.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Data modeling in Ecto takes a bit of getting used to, especially for developers that have mostly been
working with traditional &amp;quot;heavy&amp;quot; ORMs.&lt;/p&gt;
&lt;p&gt;For many novice Ecto users, association-related operations become the first stumbling stone. Ecto provides multiple
functions for establishing and modifying associations between records, each tailored to the particular use-case.
Judging from the number of questions about &lt;code&gt;cast_assoc&lt;/code&gt;, &lt;code&gt;put_assoc&lt;/code&gt; and &lt;code&gt;build_assoc&lt;/code&gt; on StackOverflow and other
online communities, choosing the right one can often be challenging, especially if the user is not yet accustomed to
the technical terminology in Ecto&amp;#39;s official documentation.&lt;/p&gt;
&lt;p&gt;The goal of this post is to give a short but definitive answer to such questions in a few of the most common
(and most simple) scenarios.&lt;/p&gt;
&lt;h2&gt;Traditional &amp;quot;Heavy&amp;quot; ORMs VS Ecto&lt;/h2&gt;
&lt;p&gt;Traditional ORMs take on the massively complicated task of &amp;quot;masking&amp;quot;
data-related operations, giving developers the illusion of working with language-native data containers.
To achieve that, ORMs often perform complex transformations behind-the-scenes, which sometimes leads to suboptimal
database performance. In this sense, ORMs propose a tradeoff between the convenience of language-native syntax and
the precision of hand-crafted SQL queries.&lt;/p&gt;
&lt;p&gt;Ecto essentially provides the same tradeoff but leans much closer to the side of hand-crafted SQL queries.
The core conceptual difference is that Ecto does not intend to abstract away the database operations, instead,
it provides an Elixir syntax for crafting &lt;em&gt;SQL queries&lt;/em&gt; themselves. Ecto relies on a developer to format
and validate the data to conform with the database schema, craft queries that use indexes efficiently, associate the
records together and perform other tasks that ORM would try to automate. The result is a somewhat higher learning curve,
but also, significantly increased flexibility. For a more in-depth comparison between ActiveRecord and Ecto,
check out this excellent &lt;a href=&quot;/2018/09/28/active-record-vs-ecto.html&quot;&gt;ActiveRecord vs. Ecto&lt;/a&gt; post.&lt;/p&gt;
&lt;p&gt;Moving forward, we&amp;#39;ll create a simple Elixir blog app which we&amp;#39;ll use throughout the article.&lt;/p&gt;
&lt;h2&gt;Creating an Example Elixir App&lt;/h2&gt;
&lt;p&gt;In your terminal, create a new Elixir app like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix new blog_app --sup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then open up &lt;code&gt;mix.exs&lt;/code&gt; and add the following dependencies to enable us to work with Ecto:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs

defmodule BlogApp.MixProject do
  use Mix.Project

  ...

  defp deps do
    [
      {:ecto_sql, &amp;quot;~&amp;gt; 3.2&amp;quot;},
      {:postgrex, &amp;quot;~&amp;gt; 0.15&amp;quot;}
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setting Up the Repo&lt;/h2&gt;
&lt;p&gt;One thing to note is that Ecto has adaptors for PostgreSQL, MySQL and SQLserver by default. Here, we are adding the PostgreSQL adaptor (we assume you already have PostgreSQL installed).
Next, run &lt;code&gt;mix deps.get&lt;/code&gt; to install the newly added dependencies. Then we need to create a repo which forms the point of contact between the app and the database:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix ecto.gen.repo -r Blog.Repo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go ahead and edit the automatically created database configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/config.exs

import Config

config :blog_app, Blog.Repo,
  database: &amp;quot;blog_app_repo&amp;quot;,
  username: &amp;quot;user&amp;quot;,
  password: &amp;quot;password&amp;quot;,
  hostname: &amp;quot;localhost&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To ensure the Ecto process is started when the app starts, we need to add the repo to the app&amp;#39;s supervisor like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/blog_app/application.ex

defmodule BlogApp.Application do

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      Blog.Repo
    ]

    ...

  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we add the &lt;code&gt;Blog&lt;/code&gt; repo to &lt;code&gt;config.exs&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# config/config.exs

import Config

...

config :blog_app, ecto_repos: [Blog.Repo]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, run &lt;code&gt;mix ecto.create&lt;/code&gt; to create the database and finalize the setup process. Next, let&amp;#39;s do a migration for a &lt;code&gt;Post&lt;/code&gt; model that we&amp;#39;ll use
in the proceeding steps.&lt;/p&gt;
&lt;h2&gt;Adding Ecto Migrations&lt;/h2&gt;
&lt;p&gt;Run the commands below to create the &lt;code&gt;Post&lt;/code&gt; and associated &lt;code&gt;Comment&lt;/code&gt; migration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;mix ecto.gen.migration create_posts -r Blog.Repo

mix ecto.gen.migration create_comments -r Blog.Repo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate two time-stamped migrations in &lt;code&gt;priv/repo/migrations&lt;/code&gt; which you should edit as shown below, starting with the &lt;code&gt;Post&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# priv/repo/migrations/XXXXXX_create_posts.exs

defmodule Blog.Repo.Migrations.CreatePosts do
  use Ecto.Migration

  def change do
    create table(:posts) do
      add(:title, :string)
      add(:body, :string)

      timestamps()
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also edit the &lt;code&gt;Comment&lt;/code&gt; migration as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# priv/repo/migrations/XXXXXX_create_comments.exs

defmodule Blog.Repo.Migrations.CreateComments do
  use Ecto.Migration

  def change do
    create table(:comments) do
      add(:body, :string)
      add(:post_id, references(:posts), null: false)

      timestamps()
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that done, run the migrations with &lt;code&gt;mix ecto.migrate&lt;/code&gt;. Finally, to use our app we need a structured
way to query the database using Ecto schemas.&lt;/p&gt;
&lt;h2&gt;Adding Ecto schemas&lt;/h2&gt;
&lt;p&gt;Although it&amp;#39;s possible to use schema-less queries, let&amp;#39;s avoid having to manually construct queries every time we need to use them.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll add the first schema for posts. Create a new file under &lt;code&gt;lib/blog/post.ex&lt;/code&gt; with the following contents:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/blog/post.ex

defmodule Blog.Post do
  use Ecto.Schema

  schema &amp;quot;posts&amp;quot; do
      has_many :comments, Blog.Comment # Here we add the asscociation to comments
    field :title, :string
    field :body, :string

    timestamps()
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We won&amp;#39;t go into the details of how to build schemas for now. If you need to dig into the topic further, &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Schema.html&quot;&gt;check out the Ecto schema docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next, create another schema to handle comments under &lt;code&gt;lib/blog/comment.ex&lt;/code&gt; and edit it as below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/blog/comment.ex

defmodule Blog.Comment do
  use Ecto.Schema

  schema &amp;quot;comments&amp;quot; do
      belongs_to :post, Blog.Post  # Here we add the asscociation to post
    field :body, :string

    timestamps()
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that, the app is ready. Let&amp;#39;s now use it to dive straight into learning more on Ecto associations.&lt;/p&gt;
&lt;h2&gt;Direct Casting of Association ID&amp;#39;s: &lt;code&gt;cast&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Working with associations doesn&amp;#39;t always have to be complex. In a situation where you have the target ID, Ecto lets
you treat the relation column as a normal database field.&lt;/p&gt;
&lt;p&gt;To give a concrete example, let&amp;#39;s assume we work with two models, &lt;code&gt;Post&lt;/code&gt; and &lt;code&gt;Comment&lt;/code&gt;, where multiple comments can
refer to a single post. In that case, your models would look something like this.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;    defmodule Blog.Post do
        use Ecto.Schema
        schema &amp;quot;posts&amp;quot; do
            has_many :comments, Blog.Comment
            field :title, :string
            field :body, :string
        end
    end

    defmodule Blog.Comment do
        use Ecto.Schema
        schema &amp;quot;posts&amp;quot; do
            belongs_to :post, Blog.Post
            field :body, :string
        end
    end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;These models reflect the following table schemas in the database:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-11/db-schema.png&quot; alt=&quot;database schema&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Each table contains a primary field &lt;code&gt;id&lt;/code&gt; by default. The &lt;code&gt;has_many&lt;/code&gt; field on &lt;code&gt;Post&lt;/code&gt; does not refer to a database field, it
only exists to hint to Ecto that it&amp;#39;s possible to preload comments for a post using the comment&amp;#39;s &lt;code&gt;belongs_to&lt;/code&gt; field.
The &lt;code&gt;belongs_to&lt;/code&gt; field, on the other hand, refers to an existing field in a table schema. By default, the name of this
field in a table is &lt;strong&gt;different&lt;/strong&gt; from the name in Ecto&amp;#39;s model: the database field has &lt;code&gt;_id&lt;/code&gt; at the end.&lt;/p&gt;
&lt;p&gt;Ecto lets you modify these kinds of association fields the same way you would modify any other field. In Ecto,
changing the value of a primitive field is called &amp;quot;casting&amp;quot;. If you need to create a new comment for a particular post,
you don&amp;#39;t really need any of the association-specific functions, you can just &lt;code&gt;cast&lt;/code&gt; the value of a primary key:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;comment
    |&amp;gt; cast(params, [:post_id, :body])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the simplest and most straightforward method of creating an association between two tables.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Casting&lt;/strong&gt; Associations: &lt;code&gt;cast_assoc&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;It is useful to think about &lt;code&gt;cast_assoc&lt;/code&gt; as a special version of &lt;code&gt;cast&lt;/code&gt; that works on associations.
However, casting associations can be much more complex than casting normal fields. The &lt;code&gt;cast&lt;/code&gt; call normally translates
more or less directly into a single SQL query, while &lt;code&gt;cast_assoc&lt;/code&gt; might result in multiple &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt; or
&lt;code&gt;DELETE&lt;/code&gt; queries. Let&amp;#39;s assume the database tables from the previous example contains the following content:&lt;/p&gt;
&lt;h5&gt;Post:&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;title&lt;/th&gt;
&lt;th&gt;body&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;A story...&lt;/td&gt;
&lt;td&gt;Once upon a time...&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h5&gt;Comment&lt;/h5&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;post_id&lt;/th&gt;
&lt;th&gt;body&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Great story!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;What happened next?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Thanks for the article&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Since the &lt;code&gt;Post&lt;/code&gt; model contains &lt;code&gt;has_many&lt;/code&gt; association to &lt;code&gt;Comment&lt;/code&gt;, it&amp;#39;s trivial to preload all comments
on a particular post:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Post
  |&amp;gt; Repo.get!(id)
  |&amp;gt; Repo.preload(:comments)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The shape of the returned data will be as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%Post{
    &amp;quot;id&amp;quot; =&amp;gt; 1,
    &amp;quot;title&amp;quot; =&amp;gt; &amp;quot;A story of...&amp;quot;,
    &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;Once upon a time...&amp;quot;,
    &amp;quot;comments&amp;quot; =&amp;gt; [
        %Comment{&amp;quot;id&amp;quot; =&amp;gt; 10, &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;Great story!&amp;quot;},
        %Comment{&amp;quot;id&amp;quot; =&amp;gt; 11, &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;What happened next?&amp;quot;},
        %Comment{&amp;quot;id&amp;quot; =&amp;gt; 12, &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;Thanks for the article&amp;quot;},
    ],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Single &lt;code&gt;cast_assoc&lt;/code&gt; call on &lt;code&gt;:comments&lt;/code&gt; will &lt;em&gt;replace&lt;/em&gt; the association as a whole. In effect, this means that the values
you pass to &lt;code&gt;cast_assoc&lt;/code&gt; will be returned in future &lt;code&gt;preload&lt;/code&gt; calls. This does &lt;strong&gt;not&lt;/strong&gt; necessarily mean that all
database rows are replaced. Ecto compares &lt;em&gt;before&lt;/em&gt; and &lt;em&gt;after&lt;/em&gt; states and does the minimal amount of work required
to reach the desired state. To illustrate that, consider the following changeset:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;params = %{comments: [
    %Comment{&amp;quot;id&amp;quot; =&amp;gt; 11, &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;What happened next?&amp;quot;},
    %Comment{&amp;quot;id&amp;quot; =&amp;gt; 12, &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;Thank you for the post&amp;quot;},
    %Comment{&amp;quot;body&amp;quot; =&amp;gt; &amp;quot;Interesting&amp;quot;},
]}
post
|&amp;gt; cast(params, [])
|&amp;gt; cast_assoc(:comments)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Executing this changeset results in three calls to the database:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DELETE&lt;/code&gt; the comment with an id of &lt;code&gt;10&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UPDATE&lt;/code&gt; the comment with the id of &lt;code&gt;12&lt;/code&gt; and set body to &amp;quot;Thank you for the post&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INSERT&lt;/code&gt; a comment with a body &amp;quot;Interesting&amp;quot; and assign it a new id.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The row with the ID of 11 was left unchanged because it matches preloaded values. An important thing to note here is that
Ecto &lt;strong&gt;will not preload data on its own&lt;/strong&gt;, so to make use of &lt;code&gt;cast_assoc&lt;/code&gt;, you need to remember to call &lt;code&gt;preload&lt;/code&gt;
beforehand. However, you are not restricted to preloading a &lt;em&gt;complete&lt;/em&gt; association. &lt;code&gt;cast_assoc&lt;/code&gt; will work just as
well when you use preload as a subset of records with &lt;code&gt;Repo.preload(:comments, query)&lt;/code&gt;. This feature is very useful for
limiting the impact of &lt;code&gt;cast_assoc&lt;/code&gt; to a subset of associated records.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Defining&lt;/strong&gt; Associations: &lt;code&gt;put_assoc&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;At first glance, &lt;code&gt;put_assoc&lt;/code&gt; is in many ways similar to &lt;code&gt;cast_assoc&lt;/code&gt;: it also works on a whole association
and requires you to pre-load records to be updated. However, upon closer examination, it turns out to be almost
opposite in the way you use it. The crucial distinction is that &lt;code&gt;put_assoc&lt;/code&gt; is designed to update
the association &amp;quot;references&amp;quot;, not the data. That is, you would typically use &lt;code&gt;put_assoc&lt;/code&gt; when you want to connect
a record to one or more records &lt;strong&gt;that already exist&lt;/strong&gt; in the database.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;put_assoc&lt;/code&gt; can be used to associate a new comment with an existing post, similar to what we did in the &amp;quot;direct casting&amp;quot;
section, but without using the &lt;code&gt;post_id&lt;/code&gt; field directly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;post = Repo.get!(7)
# ...
comment
    |&amp;gt; cast(params, [:body])
    |&amp;gt; put_assoc(:post, post)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes your code a little bit cleaner in cases with complex primary fields because Ecto does all the bookkeeping
for you.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Building&lt;/strong&gt; Related Records: &lt;code&gt;build_assoc&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;build_assoc&lt;/code&gt; is the convenience function that allows you to create related records through an association
on an existing record. To continue our post/comment example, here is another way to create a new comment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;post = Repo.get!(7)
...
comment_params = %{
    &amp;quot;title&amp;quot;: &amp;quot;A story...&amp;quot;
    &amp;quot;body&amp;quot;: &amp;quot;Once upon a time...&amp;quot;
}
Ecto.build_assoc(post, :comments, comment_params)
# %Comment{post_id: 7, title: &amp;quot;A story...&amp;quot;, body: &amp;quot;Once upon a time...&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The power of &lt;code&gt;build_assoc&lt;/code&gt; is in its expressiveness: the code above clearly shows you that comment belongs to the post.&lt;/p&gt;
&lt;p&gt;Unlike the functions discussed above, &lt;code&gt;build_assoc&lt;/code&gt; does not operate on a changeset — it builds one. This means you would
only ever use &lt;code&gt;build_assoc&lt;/code&gt; when you want to create a new record.&lt;/p&gt;
&lt;h2&gt;Wrap Up&lt;/h2&gt;
&lt;p&gt;While this post doesn&amp;#39;t begin to cover the variety of use-cases you might encounter in production applications,
I hope it gives you a strong foundation from which to begin searching for an answer. And if you need a refresher
in the future, here is a simple flowchart that will remind you of the discussed use cases:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-11/flow-assoc.png&quot; alt=&quot;Flow&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Ecto&amp;#39;s association functions are relatively thin abstractions over field references in a database. Understanding how
each of those functions works on a database level is crucial to becoming an expert Elixir/Phoenix developer. Fortunately,
Ecto is built in such a way that each function is relatively small, deterministic, and has a single purpose. After you
have mastered the basics, you can expect fewer &amp;quot;gotchas&amp;quot; compared to the traditional ORMs (or at least in my experience
that was the case). Happy coding!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Capabilities of Elixir&#039;s Logger</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/10/13/capabilities-of-elixir-logger.html"/>
    <id>https://blog.appsignal.com/2020/10/13/capabilities-of-elixir-logger.html</id>
    <published>2020-10-13T00:00:00+00:00</published>
    <updated>2020-10-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Let&#039;s find out what can be done with Elixir&#039;s Logger.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This post was updated on 9 August 2023 to reference the latest version of the Elixir logger.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Logs are an important part of your application and logging shouldn&amp;#39;t be one of the last things you think of. You should configure your log system, formatter, and style as soon as you start the development of your app. Also, do your best to document the process and share how it works with the rest of your team.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;re going to demonstrate how logs work in &lt;a href=&quot;https://elixir-lang.org/&quot;&gt;Elixir&lt;/a&gt;. We&amp;#39;ll jump into Elixir&amp;#39;s &lt;a href=&quot;https://hexdocs.pm/logger/Logger.html&quot;&gt;Logger&lt;/a&gt; module, which brings a lot of power to logging features. It also smoothly integrates with Erlang’s &lt;code&gt;:logger&lt;/code&gt; to convert code to Elixir syntax.&lt;/p&gt;
&lt;p&gt;You’ll learn how to customize your formatter, set up and change the log defaults of a &lt;a href=&quot;https://www.phoenixframework.org/&quot;&gt;Phoenix&lt;/a&gt; web API, as well as understand Logger levels a bit better.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Logs are useful but having a complete overview of your app is even better. &lt;a href=&quot;https://www.appsignal.com/elixir&quot;&gt;Check out our 5-in-1 application monitoring for Elixir&lt;/a&gt;. We&amp;#39;re free for OSS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Our Project Environment Setup&lt;/h2&gt;
&lt;p&gt;To follow along, you should have a working Elixir environment set up. You can find instructions for that on &lt;a href=&quot;https://elixir-lang.org/install.html&quot;&gt;Elixir’s Installation Page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After installation, the following command will be available:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you run that command, an Elixir Interactive Shell will be opened. This is a REPL command-line environment in which you can test Elixir commands.&lt;/p&gt;
&lt;p&gt;This is the perfect stage for some initial tests with Elixir’s &lt;a href=&quot;https://hexdocs.pm/elixir/IO.html&quot;&gt;IO&lt;/a&gt; module. As the name suggests, this module handles operations over IO, like data input and output.&lt;/p&gt;
&lt;p&gt;To check that out, run the following commands within the &lt;code&gt;iex&lt;/code&gt; shell:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IO.puts(&amp;quot;Hello world from Elixir&amp;quot;)

IO.puts(:stdio, &amp;quot;Logging from the stdio...&amp;quot;)
IO.puts(:stderr, &amp;quot;This is an error...&amp;quot;)

IO.inspect(self())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the simplest form of logging in Elixir. The &lt;code&gt;puts&lt;/code&gt; function takes two arguments, the first being the target destination of the log message (as an atom) and the second, the message itself.&lt;/p&gt;
&lt;p&gt;When called with only the &lt;code&gt;message&lt;/code&gt; argument, &lt;code&gt;IO.puts&lt;/code&gt; will print to &lt;code&gt;:stdout&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;The third line exemplifies how you could change the destination to something else, like the &lt;code&gt;:stderr&lt;/code&gt;. Although this setting changes the internal structure of the log, it doesn’t change anything in the output because there’s no color highlight being made.&lt;/p&gt;
&lt;p&gt;Finally, there’s an &lt;code&gt;inspect&lt;/code&gt; function on the last line. This function inspects the more complex structures of your Elixir application and allows you to log, for example, information about the process id in which that code is running.&lt;/p&gt;
&lt;p&gt;You can see the logs of this execution below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-08/iex-run.png&quot; alt=&quot;Execution results&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Phoenix Project&lt;/h2&gt;
&lt;p&gt;For the purposes of the article, you&amp;#39;ll also need to have a Phoenix application created from scratch.&lt;/p&gt;
&lt;p&gt;So make sure to follow the official instructions &lt;a href=&quot;https://hexdocs.pm/phoenix/installation.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since our focus is on logging, we only need the homepage and a single GET endpoint.&lt;/p&gt;
&lt;h2&gt;What About the Elixir Logger?&lt;/h2&gt;
&lt;p&gt;Among other things, Elixir’s Logger module provides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All the major levels of logging common to most languages&lt;/li&gt;
&lt;li&gt;Pre-formatting of log messages before they reach their destination&lt;/li&gt;
&lt;li&gt;Integration with Erlang’s Logger for even more power&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Logger Levels&lt;/h2&gt;
&lt;p&gt;Logger currently embraces the following log levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;:debug&lt;/strong&gt;: must be used for debug-only purposes. Be careful not to set this mode for production environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;:info&lt;/strong&gt;: the most used one. It should be triggered whenever you need to print information of any nature.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;:warn&lt;/strong&gt; and &lt;strong&gt;:error&lt;/strong&gt;: even though &lt;code&gt;:info&lt;/code&gt; can be used for everything, it’s better to finetune your warning and error messages. This way, automation tools will understand your categorized logs better.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are stacked in the exact order of precedence which Elixir considers when having to choose between one or another.&lt;/p&gt;
&lt;h2&gt;Usage Example&lt;/h2&gt;
&lt;p&gt;Its usage is pretty simple. See the following example with a string interpolation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Logger.info(&amp;quot;Hey, it&amp;#39;s me: #{user_name}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;You can also use it within the &lt;code&gt;iex&lt;/code&gt; shell. Just run the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;require Logger
user_name = &amp;quot;Julio&amp;quot;
Logger.info(&amp;quot;Hey, it&amp;#39;s me: #{user_name}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&amp;#39;s the output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;11:29:55.379 [info]  Hey, it&amp;#39;s me: Julio
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Formatter&lt;/h2&gt;
&lt;p&gt;Note that, by default, Logger comes with a preset format. In the above log, you can see a timestamp of when the event happened, the level of the log, and its message.&lt;/p&gt;
&lt;p&gt;When you work with real-world applications, like a web API, you need to define which levels are accepted for each environment.&lt;/p&gt;
&lt;p&gt;Get back to the Phoenix application you created previously and open the &lt;em&gt;config&lt;/em&gt; folder. You may see a bunch of Elixir files with names that match development, testing, and production environments. Open the &lt;em&gt;config.exs&lt;/em&gt; file, which is the boss of your app configuration and locate the &lt;code&gt;config :logger&lt;/code&gt; line.&lt;/p&gt;
&lt;p&gt;Take a brief look at these lines. This is Elixir’s Logger configuration. Whatever you change here, is going to be applied to all your app’s logs.&lt;/p&gt;
&lt;p&gt;Start by changing the default log level of the entire app. If you specify that it should be &lt;em&gt;error&lt;/em&gt; (the highest in the stack), then the others won&amp;#39;t be logged anymore. So change the first line of the config to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console,
    level: :error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To test, you’ll need to add some logs to your controller function. So, open the file &lt;em&gt;simple_controller.ex&lt;/em&gt; that’s located in the &lt;em&gt;web/controllers&lt;/em&gt; folder and switch its code to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;require Logger

defmodule SimpleElixirApi.PageController do
  use SimpleElixirApi.Web, :controller

  def index(conn, _params) do
    IO.puts(&amp;quot;I&amp;#39;m a log&amp;quot;)
    Logger.debug(&amp;quot;I&amp;#39;m a debug log&amp;quot;)
    Logger.info(&amp;quot;I&amp;#39;m an info log&amp;quot;)
    Logger.warn(&amp;quot;I&amp;#39;m a warn log&amp;quot;)
    Logger.error(&amp;quot;I&amp;#39;m an error log&amp;quot;)

    Logger.metadata(request_id: &amp;quot;123&amp;quot;)
    render(conn, &amp;quot;index.html&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart your server and hit the &lt;a href=&quot;http://localhost:4000/&quot;&gt;http://localhost:4000/&lt;/a&gt; address again. You should see the following in your console:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-10/image3.png&quot; alt=&quot;Error logs are shown in the console&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Change the level to the others and check out the results. Remember that you may configure each of the environment files separately to avoid log setting confusion.&lt;/p&gt;
&lt;h3&gt;Message Formatter&lt;/h3&gt;
&lt;p&gt;Alternatively, you can format your log messages by providing a regex. Change your Logger config (at &lt;em&gt;configs.ex&lt;/em&gt;) to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console,
    level: :info,
    format: &amp;quot;$time $message $metadata[$level] \n&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the level was changed to allow more log lines for comparison.&lt;/p&gt;
&lt;p&gt;Here, the format is receiving only the log’s variables to be injected into the output. However, you can customize with any of &lt;a href=&quot;https://hexdocs.pm/elixir/Regex.html&quot;&gt;Elixir’s regex&lt;/a&gt; that may please you.&lt;/p&gt;
&lt;p&gt;This should be the output:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-10/image4.png&quot; alt=&quot;Custom formatted messages&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In the end, it hasn’t changed that much. However, this was on purpose. For more advanced logs, you’ll need to write your own formatter.&lt;/p&gt;
&lt;h2&gt;Creating Your Formatter&lt;/h2&gt;
&lt;p&gt;Elixir’s config allows you to create and set your own formatter. With it, you have the option of creating whatever routines you want before, during, and after each log reaches its destination.&lt;/p&gt;
&lt;p&gt;To make this happen, you’ll need to create a new logger module. So, within the &lt;em&gt;lib&lt;/em&gt; folder, create another one called &lt;em&gt;logger&lt;/em&gt; and create a file named &lt;em&gt;my_logger.ex&lt;/em&gt; inside it with the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Logger.MyLogger do
    def format(level, message, timestamp, metadata) do
      &amp;quot;time=#{timestamp} level=[#{level}] metadata=#{inspect(metadata)} message=#{message}\n&amp;quot;
    rescue
      _ -&amp;gt; &amp;quot;Ooops, there was an error here!\n&amp;quot;
    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can name the function whatever you want but it’s common practice to give it the &lt;code&gt;format&lt;/code&gt; name. It basically receives all common log attributes and formats them into a predefined pattern.&lt;/p&gt;
&lt;p&gt;The message obeys the usual pattern for maps (key=value), very common among log processing tools.&lt;/p&gt;
&lt;p&gt;In case anything goes wrong, an error message will be thrown at the &lt;code&gt;rescue&lt;/code&gt; block.&lt;/p&gt;
&lt;p&gt;For it to run, the Elixir config file has to be aware of it, so change the logger config to the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console,
    level: :info,
    format: {Logger.MyLogger, :format}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Restart the server and check out how your logs look now.&lt;/p&gt;
&lt;h2&gt;Logging Metadata&lt;/h2&gt;
&lt;p&gt;Another useful feature that comes built-in with Elixir’s Logger is &lt;a href=&quot;https://hexdocs.pm/logger/Logger.html#module-metadata&quot;&gt;metadata&lt;/a&gt; logging.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&amp;#39;re using AppSignal to monitor your app, instead of adding metadata to your logs, you can &lt;a href=&quot;https://docs.appsignal.com/elixir/instrumentation/tagging.html&quot;&gt;add sample data to your AppSignal samples by using tagging&lt;/a&gt;. This way you can supply extra context on errors and performance issues.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are times when you need to group a bunch of information in categorized logs. Since you’re under Phoenix&amp;#39;s wing, your web APIs may need to automatically show some data related to HTTP requests and responses, like the request’s id.&lt;/p&gt;
&lt;p&gt;Logger metadata works as a list of keywords (similar to maps and dictionaries) that’s exclusive to the running process (which means that, in the HTTP fandom, one request won’t get affected by others).&lt;/p&gt;
&lt;p&gt;Every time a request arrives in the house, Logger will catch it, check your log configs and ask what metadata keywords are allowed to be logged.&lt;/p&gt;
&lt;p&gt;You can define them one by one or tell Logger to consider them all:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :console,
    level: :info,
    format: {Logger.MyLogger, :format},
    metadata: [:request_id]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To set them all, just change the &lt;code&gt;metadata&lt;/code&gt; config to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;metadata: :all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do you remember the code line you added to the controller a few moments ago:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Logger.metadata(request_id: &amp;quot;123&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can check out the request’s id appearing in your logs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;12:08:13.040 metadata=[request_id=123] [info] My request log
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Logging to Files&lt;/h2&gt;
&lt;p&gt;Perhaps one of the easiest features within Logger is changing the log’s destination to a file rather than the default console.&lt;/p&gt;
&lt;p&gt;First, you need to set up a new backend for the &lt;code&gt;logger_file_backend&lt;/code&gt; package:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger,
    backends: [{LoggerFileBackend, :debug_log}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you specify the destination file that Logger will send the logs to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :logger, :debug_log,
    path: &amp;#39;myLog.log&amp;#39;,
    level: :debug
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you &lt;code&gt;tail -f&lt;/code&gt; your &lt;em&gt;myLog.log&lt;/em&gt; file, you should see the logs.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;It’s unbelievable how such a simple subject as logging can lead to a lot of unseen extra information.
Right now, Elixir&amp;#39;s Logger is tightly integrated with Erlang’s, so that developers can now &lt;a href=&quot;https://hexdocs.pm/logger/1.12.3/Logger.html#module-erlang-otp-handlers&quot;&gt;implement custom loggers&lt;/a&gt;.
Good luck with exploring Elixir loggging!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Monitoring Any System with StatsD and AppSignal&#039;s Standalone Agent</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/09/23/monitoring-any-system-with-statsd-and-the-standalone-appsignal-agent.html"/>
    <id>https://blog.appsignal.com/2020/09/23/monitoring-any-system-with-statsd-and-the-standalone-appsignal-agent.html</id>
    <published>2020-09-23T00:00:00+00:00</published>
    <updated>2020-09-23T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">To extend monitoring everywhere and have all data in a single place, check out our standalone agent.</summary>
    <content type="html">&lt;p&gt;Monitoring your application alone is not always enough to get the full picture of your systems. Frequently, services running in satellite apps (or supporting apps) can have an acute impact on your day-to-day operations. Database servers are well-known examples of this. Backup scripts and other background jobs can also slow systems and are often overlooked.&lt;/p&gt;
&lt;p&gt;The AppSignal &lt;a href=&quot;https://www.appsignal.com/nodejs&quot;&gt;APM for Node.js&lt;/a&gt;, and the &lt;a href=&quot;https://www.appsignal.com/ruby/&quot;&gt;Ruby APM&lt;/a&gt; and &lt;a href=&quot;https://www.appsignal.com/elixir/&quot;&gt;Elixir APM&lt;/a&gt; automatically instrument your app itself. But AppSignal does not watch these satellite processes by default. To extend monitoring everywhere and have all your data in a single app, you can install AppSignal’s &lt;a href=&quot;https://docs.appsignal.com/standalone-agent/installation.html&quot;&gt;standalone agent&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;AppSignal&amp;#39;s Standalone Agent&lt;/h2&gt;
&lt;p&gt;The standalone agent is based on the &lt;a href=&quot;https://docs.appsignal.com/appsignal/how-appsignal-operates.html#agent&quot;&gt;same software&lt;/a&gt; with which we usually instrument Ruby, Elixir, or JavaScript applications. This software can also run in standalone mode.&lt;/p&gt;
&lt;p&gt;The standalone agent can be used to monitor:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt;: machines that are part of our system but do not run application code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background jobs&lt;/strong&gt;: such as intensive cron jobs or long-running data-processing scripts. If these background jobs are written in a supported language (Ruby, Elixir, or Node.js) you can use the standard integration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More languages&lt;/strong&gt;: programs written in languages other than those supported out of the box.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For instance, with the standalone agent, we could track a machine learning model written in Python, instrument backup scripts, &lt;a href=&quot;/2020/07/07/how-appsignal-monitors-their-own-kafka-brokers.html&quot;&gt;monitor Kafka brokers&lt;/a&gt;, or collect &lt;a href=&quot;https://docs.appsignal.com/metrics/host-metrics/index.html&quot;&gt;host metrics&lt;/a&gt; in our web farms. You can view all this information on AppSignal to complement the metrics you already have for your main applications.&lt;/p&gt;
&lt;h2&gt;How It Works&lt;/h2&gt;
&lt;p&gt;The agent is shipped as a deb or rpm package and doesn’t have any language dependencies. It runs in any Debian/Ubuntu or Red Hat-based systems. For detailed installation instructions, check the &lt;a href=&quot;https://docs.appsignal.com/standalone-agent/installation.html#installation&quot;&gt;agent documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once installed, the agent is configured in a few minutes and keeps running forever as a daemon, silently monitoring your infrastructure. What is more, the agent includes a &lt;a href=&quot;https://docs.appsignal.com/standalone-agent/statsd.html&quot;&gt;StatsD&lt;/a&gt; server that relays any custom data you log into your AppSignal dashboard.&lt;/p&gt;
&lt;h3&gt;What Is StatsD?&lt;/h3&gt;
&lt;p&gt;StatsD is a standard for collecting and aggregating arbitrary data. It focuses on logging metric and performance information. It uses a lightweight text protocol over UDP connections that have a small footprint in your machine.&lt;/p&gt;
&lt;p&gt;A StatsD message looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;KEY:VALUE|TYPE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;KEY&lt;/code&gt; is any arbitrary string, and &lt;code&gt;VALUE&lt;/code&gt; is a number. The type value defines how the number is processed.&lt;/p&gt;
&lt;p&gt;We support three types of metrics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;c&lt;/strong&gt;: this is a &lt;em&gt;counter&lt;/em&gt; that increments each time it is called. For instance, &lt;code&gt;active_users:1|c&lt;/code&gt; adds 1 to the &lt;code&gt;active_users&lt;/code&gt; counter.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;g&lt;/strong&gt;: a &lt;em&gt;gauge&lt;/em&gt; takes a numeric value and maintains it until updated. This is useful to record values that change up and down over time, such as throughput, number of active users, or number of pending tasks in a queue.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;t&lt;/strong&gt;: stores &lt;em&gt;timing&lt;/em&gt; values. This type is ideal for tracking durations. AppSignal calculates means, count, and percentiles for all the logged timings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other unsupported metric types will be silently ignored.&lt;/p&gt;
&lt;h2&gt;Sending Data to StatsD&lt;/h2&gt;
&lt;p&gt;The standalone agent listens for UDP packets on port 8125. We can send StatsD-formatted strings from the command line using &lt;a href=&quot;http://netcat.sourceforge.net/&quot;&gt;netcat&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo -n &amp;quot;myscript.myevent.counter:1|c&amp;quot; | nc -4u -w0 localhost 8125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we’re using UDP, we don’t have to wait for a response.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.dest-unreach.org/socat/&quot;&gt;Socat&lt;/a&gt; also works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo -n &amp;quot;myscript.myevent.counter:1|c&amp;quot; | socat - udp:localhost:8125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes it easy to instrument any batch or cron jobs. For instance, the following lines use a gauge to log how much data a backup job has generated:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;backup_size=$(du -m /backups | cut -f1)
echo -n &amp;quot;backup.data:$backup_size|g&amp;quot; | nc -4u -w0 localhost 8125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re not limited to integers. StatsD also works with floating-point numbers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo -n &amp;quot;network.latency:0.2|g&amp;quot; | nc -4u -w0 localhost 8125
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Using Tags&lt;/h2&gt;
&lt;p&gt;You can add tags to your metrics. The StatsD server supports optional tags at the end of the message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;KEY:VALUE|TYPE|#TAGS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can apply several tags in the same message and assign values for filtering later:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo -n &amp;quot;backup.data:$backup_size|g|#backups,env:production&amp;quot; | nc -4u -w0 localhost 8125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’ll learn how to see the data in AppSignal in a bit.&lt;/p&gt;
&lt;h2&gt;Instrumenting Languages&lt;/h2&gt;
&lt;p&gt;The StatsD server is compatible with any language that can send UDP packets. Let’s see a few examples.&lt;/p&gt;
&lt;p&gt;Python is a popular language for data mining and machine learning. We can add instrumentation into Python applications using the build-in &lt;code&gt;socket&lt;/code&gt; library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import time

# measure time taken for function
start = time.process_time()
train_my_model()
training_time = time.process_time() - start

# send value to statsd
import socket

UDP_IP = &amp;quot;127.0.0.1&amp;quot;
UDP_PORT = 8125
MESSAGE = b&amp;quot;model.training.time:&amp;quot; + bytes(str(training_time), &amp;#39;utf-8&amp;#39;) + b&amp;quot;|t&amp;quot;

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We could achieve similar results in Java with the &lt;code&gt;java.net&lt;/code&gt; library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;byte[] buffer = &amp;quot;mybatch.exception.counter:1|c&amp;quot;.getBytes();
InetAddress address = InetAddress.getByName(&amp;quot;127.0.0.1&amp;quot;);
DatagramPacket packet = new DatagramPacket(
    buffer, buffer.length, address, 8125
);
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.send(packet);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PHP is another example of an incredibly popular language. We can send UDP packets with &lt;code&gt;socket_sendto&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$msg = &amp;quot;mywebsite.active_users:$ACTIVE_USERS|g&amp;quot;;
$len = strlen($msg);

$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_sendto($sock, $msg, $len, 0, &amp;#39;127.0.0.1&amp;#39;, 8125);
socket_close($sock);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;StatsD Clients&lt;/h3&gt;
&lt;p&gt;Thus far, we used the built-in networking capabilities in every language. But there’s more. Many languages and products include third-party StatsD clients or addons. Any StatsD-compliant client should work, at least for the supported data types. You can find a list of clients at the &lt;a href=&quot;https://github.com/statsd/statsd/wiki&quot;&gt;StatsD project wiki&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Viewing Host Data in AppSignal&lt;/h2&gt;
&lt;p&gt;The &lt;strong&gt;Host Metrics&lt;/strong&gt; dashboard shows your machine’s resource utilization:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/hosts-dashboard.png&quot; alt=&quot;Hosts metrics dashboard location&quot;/&gt;&lt;/p&gt;
&lt;p&gt;AppSignal adds an entry for every machine running the standalone agent.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/host-ov.png&quot; alt=&quot;Available hosts&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The dashboard shows the load and CPU averages disk, network, memory, and swap usage:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/hosts1.png&quot; alt=&quot;Host dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/hosts2.png&quot; alt=&quot;Host 2&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Creating Dashboards&lt;/h2&gt;
&lt;p&gt;AppSignal doesn’t automatically generate dashboards for the StatsD value you sent—you’ll need to create custom dashboards for this.&lt;/p&gt;
&lt;p&gt;First, click on &lt;strong&gt;Add dashboard&lt;/strong&gt; under the dashboard menu:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/dash0.png&quot; alt=&quot;Location of the create dashboard button&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Give a name to the dashboard:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/dash1.png&quot; alt=&quot;Creating a dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Clicking the &lt;strong&gt;Add graph&lt;/strong&gt; button shows the graph builder:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/dash2.png&quot; alt=&quot;Empty custom dashboard&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Give a name to the graph, and click on &lt;strong&gt;Add metric&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/create1.png&quot; alt=&quot;Creating a graph&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Pick the metric you’re interested in from the menu.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/backup1.png&quot; alt=&quot;Adding metrics to the graph&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Optionally, use tags for filtering:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/backup2.png&quot; alt=&quot;Filtering by tags&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Next, click &lt;strong&gt;Back to overview&lt;/strong&gt;. You might want to try different graph types and value units to find out which one best suits the data you want to represent.&lt;/p&gt;
&lt;p&gt;Timing data looks better with area graphs because the mean and percentiles are shown more clearly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/stats-timer.png&quot; alt=&quot;Changing display settings&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Line graphs work great for counters and gauges.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/create2.png&quot; alt=&quot;Create 2&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Once you’re happy with the result, click on &lt;strong&gt;Create graph&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-09/backup3.png&quot; alt=&quot;New graph created&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Note that you can also add a dashbaord for any other automatically instrumented or measured metrics if you have AppSignal set of as your &lt;a href=&quot;https://www.appsignal.com/nodejs&quot;&gt;performance monitoring tool (APM) for Node.js&lt;/a&gt;, or your &lt;a href=&quot;https://www.appsignal.com/ruby/&quot;&gt;Ruby (on Rails) APM&lt;/a&gt; or &lt;a href=&quot;https://www.appsignal.com/elixir/&quot;&gt;Elixir APM&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;We’ve learned how to use AppSignal’s standalone server to watch your machines and satellite code. With its built-in StatsD server, you can record arbitrary performance data and instrument any process.&lt;/p&gt;
&lt;p&gt;Check the following links to learn more about using the standalone agent:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://appsignal.com&quot;&gt;StatsD reference&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.appsignal.com/metrics/custom.html&quot;&gt;How to send custom metrics&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.appsignal.com/metrics/dashboards.html&quot;&gt;Creating dashboards in AppSignal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/2020/08/17/identifying-and-resolving-a-kafka-issue-with-appsignal.html&quot;&gt;Identifying and Resolving a Kafka Issue the Standalone Agent&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Testing the Tricky Parts of an Absinthe Application</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/08/19/testing-absinthe.html"/>
    <id>https://blog.appsignal.com/2020/08/19/testing-absinthe.html</id>
    <published>2020-08-19T00:00:00+00:00</published>
    <updated>2020-08-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this post, we&#039;ll go through ways of making testing Absinthe easier</summary>
    <content type="html">&lt;p&gt;Today, we hope to make testing Absinthe a bit easier for you. We believe that it&amp;#39;s a great library for writing GraphQL applications, but if you previously haven&amp;#39;t done much
work on an Absinthe application, you might find some things a bit tricky to test.&lt;/p&gt;
&lt;p&gt;The worst part of this is that some of these really tricky things to test are some of the
best parts of Absinthe, and so, with them being a bit hard to test, folks might end up not using
those parts of the library as much as they should.&lt;/p&gt;
&lt;h2&gt;Today&amp;#39;s Ingredients&lt;/h2&gt;
&lt;p&gt;The main ingredient today is a GraphQL schema representing a blog. There are also some references to things that we&amp;#39;re not going to show, but to avoid unnecessary complexity, we will assume that
they&amp;#39;re there and working as expected. For example, we&amp;#39;re not going to be looking
at the &amp;quot;application&amp;quot; logic in modules like &lt;code&gt;MyApp.Comments&lt;/code&gt;, as we don&amp;#39;t need to do that in order to understand the testing that we&amp;#39;ll carry out.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s our main ingredient: the GraphQL schema below that represents a blog.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyAppWeb.Schema do
  use Absinthe.Schema

  import Absinthe.Resolution.Helpers

  alias MyApp.{Comments, Posts, Repo, User, Users}

  @impl true
  def context(ctx) do
    loader =
      Dataloader.new()
      |&amp;gt; Dataloader.add_source(Comments, Dataloader.Ecto.new(Repo))
      |&amp;gt; Dataloader.add_source(Posts, Dataloader.Ecto.new(Repo))
      |&amp;gt; Dataloader.add_source(Users, Dataloader.Ecto.new(Repo))

    Map.put(ctx, :loader, loader)
  end

  # This is only public so we can show how to test it later 😀
  def resolve_unread_posts(user, _, %{loader: loader}) do
    loader
    |&amp;gt; Dataloader.load(Users, :posts, user)
    |&amp;gt; Absinthe.Resolution.Helpers.on_load(fn loader -&amp;gt;
      unread_posts =
        loader
        |&amp;gt; Dataloader.get(Users, :posts, user)
        |&amp;gt; Enum.filter(&amp;amp; !&amp;amp;1.is_read)

      {:ok, unread_posts}
    end)
  end

  object :user do
    field(:name, non_null(:string))
    field(:age, non_null(:integer))
    field(:posts, non_null(list_of(non_null(:post))), resolve: dataloader(Posts))
    field(:unread_posts, non_null(list_of(non_null(:post)), resolve: &amp;amp;resolve_unread_posts/3)
  end

  object :post do
    field(:title, non_null(:string))
    field(:body, non_null(:string))
    field(:is_read, non_null(:boolean))
    field(:comments, non_null(list_of(non_null(:comment))), resolve: dataloader(Comments))
  end

  object :comment do
    field(:body, non_null(:string))
    field(:user, non_null(:user), resolve: dataloader(Users))
  end

  query do
    field(:users, non_null(list_of(non_null(:user))), resolve: fn _, _, _ -&amp;gt; Repo.all(User) end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What to Test and Where&lt;/h2&gt;
&lt;p&gt;When you&amp;#39;ve got a GraphQL API and you&amp;#39;re using Absinthe, it means you generally have three
&amp;quot;layers&amp;quot; in your application that you can test. They are (from the outermost layer to the
innermost layer):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Document resolution&lt;/strong&gt; — where you actually send a GraphQL document as a user would and resolve
that document&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resolver functions&lt;/strong&gt; — which are just functions and so can be tested in the normal way that you&amp;#39;d
test any other function&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your application functions&lt;/strong&gt; — which is basically everything else 😀&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Like in any other application, you&amp;#39;ll be writing tests at each of these levels. The number of
tests you write at each level, and what you test, is often a matter of personal
preference.&lt;/p&gt;
&lt;h2&gt;Reason to Test at These Levels in Absinthe&lt;/h2&gt;
&lt;p&gt;The important thing is: because of how certain kinds of behavior are separated in Absinthe, and in the way
it resolves documents, there is some behavior that can &lt;em&gt;only&lt;/em&gt; be tested at some levels. For
example, if you&amp;#39;re using the default resolution function for a field in an object, you can only
test the resolution of that field at the document resolution level.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Similarly, if you&amp;#39;re using any of the &lt;a href=&quot;https://hexdocs.pm/absinthe/Absinthe.Resolution.Helpers.html#dataloader/3&quot;&gt;&lt;code&gt;Absinthe.Resolution.Helpers.dataloader&lt;/code&gt;&lt;/a&gt;
functions, you won&amp;#39;t be able to test that behavior anywhere but at the document resolution level.
This is a bit of a pattern actually — using &lt;code&gt;Dataloader&lt;/code&gt; is basically a necessity for most
GraphQL applications, but using it also makes that behavior a bit harder to test and also forces
us to test certain behavior at a higher level, in a more expensive test than one might want.&lt;/p&gt;
&lt;h2&gt;Testing Document Resolution&lt;/h2&gt;
&lt;p&gt;So let&amp;#39;s focus on testing at document resolution. Since we know we&amp;#39;re going to have to write some tests where we&amp;#39;re resolving an actual
document, we should ensure that those tests are as valuable to us as they can be! Since these will
already be rather expensive tests given that they cover the &lt;em&gt;entire&lt;/em&gt; stack, you might as well try
and squeeze all the value out of them that you can. These tests will end up being rather large,
and hopefully, you won&amp;#39;t have to have too many of them.&lt;/p&gt;
&lt;p&gt;One thing I see somewhat frequently is folks trying to make these tests smaller and more manageable, but this comes with some potential
issues. One of the great things about GraphQL is that clients can send a document that only requests the
data they need, making it easy to compose bits of functionality together into a larger API.&lt;/p&gt;
&lt;p&gt;However, this means that it&amp;#39;s also really easy to accidentally &lt;em&gt;miss&lt;/em&gt; functionality when testing
an object&amp;#39;s resolution! This can lead to errors when resolving a field in a type that isn&amp;#39;t seen
until that field is actually requested by a client in production, and that&amp;#39;s not good.&lt;/p&gt;
&lt;p&gt;So, the thing that I&amp;#39;ve relied on is the rule that when I&amp;#39;m testing document resolution, I
always request every field in whichever object I&amp;#39;m testing.&lt;/p&gt;
&lt;h2&gt;How to Request Every Field in a Test&lt;/h2&gt;
&lt;p&gt;But how do we make this easy to do? Luckily, there&amp;#39;s a function for that! In the &lt;code&gt;assertions&lt;/code&gt; library, there are some &lt;a href=&quot;https://hexdocs.pm/assertions/Assertions.Absinthe.html#content&quot;&gt;helpers for testing Absinthe applications&lt;/a&gt;.
Included in those helpers, is the &lt;a href=&quot;https://hexdocs.pm/assertions/Assertions.Absinthe.html#document_for/4&quot;&gt;&lt;code&gt;document_for/4&lt;/code&gt; function&lt;/a&gt; which automatically creates a document with all fields in the given object and will also
recursively include all fields in any associated objects to a given level of depth! The default there is 3, but since we want 4 levels deep we&amp;#39;ll need to override that. So, instead of a test
that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;resolves correctly&amp;quot;, %{user: user} do
  query = &amp;quot;&amp;quot;&amp;quot;
  query {
    users {
      name
      age
      posts {
        title
        body
        isRead
        comments {
          body
          user {
            name
            age
          }
        }
      }
      unreadPosts {
        title
        body
        isRead
        comments {
          body
          user {
            name
            age
          }
        }
      }
    }
  }
  &amp;quot;&amp;quot;&amp;quot;

  assert {:ok, %{data: data}} =
           Absinthe.run(query, MyAppWeb.Schema, context: %{current_user: user})

  assert %{
            &amp;quot;users&amp;quot; =&amp;gt; [
              %{
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;username&amp;quot;,
                &amp;quot;age&amp;quot; =&amp;gt; 35,
                &amp;quot;posts&amp;quot; =&amp;gt; [
                  %{
                    &amp;quot;title&amp;quot; =&amp;gt; &amp;quot;post title&amp;quot;,
                    &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;post body&amp;quot;,
                    &amp;quot;isRead&amp;quot; =&amp;gt; false,
                    &amp;quot;comments&amp;quot; =&amp;gt; [
                      %{
                        &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;comment body&amp;quot;,
                        &amp;quot;user&amp;quot; =&amp;gt; %{
                          &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;username&amp;quot;,
                          &amp;quot;age&amp;quot; =&amp;gt; 35
                        }
                      }
                    ]
                  }
                ],
                &amp;quot;unreadPosts&amp;quot; =&amp;gt; [
                  %{
                    &amp;quot;title&amp;quot; =&amp;gt; &amp;quot;post title&amp;quot;,
                    &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;post body&amp;quot;,
                    &amp;quot;isRead&amp;quot; =&amp;gt; false,
                    &amp;quot;comments&amp;quot; =&amp;gt; [
                      %{
                        &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;comment body&amp;quot;,
                        &amp;quot;user&amp;quot; =&amp;gt; %{
                          &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;username&amp;quot;,
                          &amp;quot;age&amp;quot; =&amp;gt; 35
                        }
                      }
                    ]
                  }
                ]
              }
            ]
          } = data
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As an exampe, we can have a test that looks like this instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;resolves correctly&amp;quot;, %{user: user} do
  query = &amp;quot;&amp;quot;&amp;quot;
  query {
    users {
      #{document_for(:user, 4)}
    }
  }
  &amp;quot;&amp;quot;&amp;quot;

  assert_response_matches(query, context: %{current_user: user}) do
    %{
      &amp;quot;users&amp;quot; =&amp;gt; [
        %{
          &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;username&amp;quot;,
          &amp;quot;age&amp;quot; =&amp;gt; 35,
          &amp;quot;posts&amp;quot; =&amp;gt; [
            %{
              &amp;quot;title&amp;quot; =&amp;gt; &amp;quot;post title&amp;quot;,
              &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;post body&amp;quot;,
              &amp;quot;isRead&amp;quot; =&amp;gt; false,
              &amp;quot;comments&amp;quot; =&amp;gt; [
                %{
                  &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;comment body&amp;quot;,
                  &amp;quot;user&amp;quot; =&amp;gt; %{
                    &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;username&amp;quot;,
                    &amp;quot;age&amp;quot; =&amp;gt; 35
                  }
                }
              ]
            }
          ],
          &amp;quot;unreadPosts&amp;quot; =&amp;gt; [
            %{
              &amp;quot;title&amp;quot; =&amp;gt; &amp;quot;post title&amp;quot;,
              &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;post body&amp;quot;,
              &amp;quot;isRead&amp;quot; =&amp;gt; false,
              &amp;quot;comments&amp;quot; =&amp;gt; [
                %{
                  &amp;quot;body&amp;quot; =&amp;gt; &amp;quot;comment body&amp;quot;
                  &amp;quot;user&amp;quot; =&amp;gt; %{
                    &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;username&amp;quot;,
                    &amp;quot;age&amp;quot; =&amp;gt; 35
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also gives us the added benefit of automatically querying any new fields as they&amp;#39;re added to
types instead of needing to manually add those new fields in all the tests in which that type is
used, further increasing the value of our existing tests!&lt;/p&gt;
&lt;p&gt;We can also see in the example above that we&amp;#39;re using the &lt;a href=&quot;https://hexdocs.pm/assertions/Assertions.Absinthe.html#assert_response_matches/4&quot;&gt;&lt;code&gt;assert_response_matches/4&lt;/code&gt;&lt;/a&gt;
macro which gives us a really nice way to match against the response from our query. This is a
pretty small wrapper around the &amp;quot;default&amp;quot; way of testing document resolution shown in the original
example, but it gives us a great symmetry between the document and the response and also serves
as really great documentation! This way, you see the intended shape of the response clearly
in the test, which could make this a valuable test even for non-Elixir developers to use as
guidance on how to use this API.&lt;/p&gt;
&lt;p&gt;But, in general, by taking this comprehensive approach to testing at this level with the guideline
of trying to have at least one of these tests covering every object in your GraphQL schema, you
should have some confidence that at the very least, every type in your schema can resolve without
error, and it helps us know that if we&amp;#39;re using Dataloader, we&amp;#39;re able to successfully resolve
those associations.&lt;/p&gt;
&lt;h2&gt;Testing Resolver Functions Using Dataloader&lt;/h2&gt;
&lt;p&gt;The final part of testing that we&amp;#39;d like to talk about since they are tricky to test is testing resolver functions that use Dataloader&amp;#39;s &lt;code&gt;on_load/2&lt;/code&gt; function. They are a bit tricky because these functions return a middleware tuple instead of something a bit easier to test. This means
that many people test the behavior in these functions at the document resolution level, but that&amp;#39;s
not strictly necessary! If you take a look at the tuple that&amp;#39;s returned, you&amp;#39;ll see the trick to
testing those functions.&lt;/p&gt;
&lt;p&gt;That function returns a tuple that looks like &lt;code&gt;{:middleware, Absinthe.Middleware.Dataloader, {loader, function}}&lt;/code&gt;,
and so many folks might expect it to be hard to test, but it&amp;#39;s not! If we want to test
the actual behavior in that function, which in this case is basically just that &lt;code&gt;Enum.filter/2&lt;/code&gt;
call, then we can write our test like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;test &amp;quot;only returns unread posts&amp;quot; do
  context = MyApp.Schema.context(%{})
  {_, _, {loader, callback}} = resolve_unread_posts(user, nil, context)

  assert {:ok, [%{is_read: false}]} =
    loader
    |&amp;gt; Dataloader.run()
    |&amp;gt; callback.()
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s not too bad, right? It just required us to look at the return value from the middleware.
All we needed for the test was right there! That callback function that is returned in that
middleware tuple is the function that&amp;#39;s actually called by Absinthe when resolving the field.
Given that the majority of your database access in an Absinthe application &lt;em&gt;should&lt;/em&gt; be going
through Dataloader, knowing how to use and test functions like this is going to be very helpful as
your application develops and more complicated functionality is needed.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve now seen the three levels of testing that we have at our disposal, how to test at the
document resolution level without missing critical pieces of the application, and how to test
those tricky functions that use Dataloader. With these three things in mind, testing your Absinthe
application should, hopefully, be much easier and more robust.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The State of Elixir HTTP Clients</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/07/28/the-state-of-elixir-http-clients.html"/>
    <id>https://blog.appsignal.com/2020/07/28/the-state-of-elixir-http-clients.html</id>
    <published>2020-07-28T00:00:00+00:00</published>
    <updated>2020-07-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Take a deep dive into Elixir HTTP client libraries — Mint and Finch.</summary>
    <content type="html">&lt;p&gt;In today&amp;#39;s post, we&amp;#39;ll look at two Elixir HTTP client libraries: &lt;a href=&quot;https://github.com/elixir-mint/mint&quot;&gt;Mint&lt;/a&gt; and &lt;a href=&quot;https://github.com/keathley/finch&quot;&gt;Finch&lt;/a&gt;. Finch is built on top of Mint. We&amp;#39;ll see the benefits offered by this abstraction layer. We&amp;#39;ll also talk about some of the existing HTTP client
libraries in the ecosystem and discuss some of the things that make Mint and Finch different. Finally, we&amp;#39;ll put
together a quick project that makes use of Finch to put all of our learning into action.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s jump right in!&lt;/p&gt;
&lt;h2&gt;What Tools Are Currently Available in the Elixir Ecosystem?&lt;/h2&gt;
&lt;p&gt;While an HTTP client may not be the most interesting part of your application, more than likely you&amp;#39;ll use an HTTP
client at some point to interface with 3rd party resources or even internal HTTP microservices. Having an HTTP client
with usable ergonomics and a friendly API can help ensure that you deliver application features quickly.&lt;/p&gt;
&lt;p&gt;If you are looking for something that comes with the BEAM, you can leverage &lt;a href=&quot;http://erlang.org/doc/man/httpc.html&quot;&gt;the &lt;code&gt;:httpc&lt;/code&gt; module&lt;/a&gt;. While &lt;code&gt;:httpc&lt;/code&gt; works great for simple requests, it
can be limiting at times, given it doesn&amp;#39;t have built-in support for connection pools, SSL verification requires a bit
of a ceremony to get set up and the API is not the most intuitive to work with
(&lt;a href=&quot;https://blog.voltone.net/post/7&quot;&gt;see this article for more information&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;HTTPoison is a 3rd party library that provides some nice abstractions on top of the Erlang library Hackney in order to
provide a nice developer experience from within Elixir. It also supports some nice features such as connection pools and
the ability to create HTTP client library modules via &lt;code&gt;use HTTPoison.Base&lt;/code&gt;. Unfortunately, in the past, I have
experienced issues with Hackney in high traffic applications (&lt;a href=&quot;http://big-elephants.com/2019-05/gun/&quot;&gt;so have other
users&lt;/a&gt;). If I suspect that I will be making a large number of concurrent requests
to an HTTP API, I try to keep that in mind and plan for possible failure scenarios.&lt;/p&gt;
&lt;p&gt;Tesla provides additional abstraction layers in the form of an HTTP client that can be configured using middlewares (similar to
Plug), mock responses for testing, and even different adapters to perform the HTTP requests. In fact, you can even use
Mint as an adapter in Tesla. If I&amp;#39;m making a very involved HTTP client with many different interactions and behaviors,
I&amp;#39;ll usually reach for Tesla as it makes it easy to package these pieces of functionality together, and the testing
utilities make your ExUnit tests very clean.&lt;/p&gt;
&lt;h2&gt;How Are Mint and Finch Different?&lt;/h2&gt;
&lt;p&gt;The previously mentioned tools all rely on a process to keep track of the ongoing HTTP connection. Mint on the other
hand provides a low-level, process-less API for interacting with TCP/SSL sockets. Every time you interact with Mint, for
example, you&amp;#39;ll be given back a new &lt;code&gt;Mint.HTTP1&lt;/code&gt; or &lt;code&gt;Mint.HTTP2&lt;/code&gt; struct handler. In addition, any data coming into the
socket will be sent as a message to the process that initiated the connection. This data can then be captured via a
simple &lt;code&gt;receive&lt;/code&gt; block and handled accordingly. While this may seem limiting, it is by design. The architecture of Mint
lends itself to being extensible and enables other library authors to wrap Mint however they see fit.&lt;/p&gt;
&lt;p&gt;This is where Finch comes in. Finch is a library that wraps Mint and provides many of the HTTP client features that you
would expect from a fully-fledged HTTP client. For example, with Finch, you get connection pooling and request &lt;a href=&quot;https://github.com/beam-telemetry/telemetry&quot;&gt;Telemetry&lt;/a&gt;
out-of-the-box. While that feature set may not be as thorough as HTTPoison or Tesla, Finch is very much focused on
being lightweight and performant.&lt;/p&gt;
&lt;h2&gt;Hands-On Project&lt;/h2&gt;
&lt;p&gt;Now that we&amp;#39;ve discussed some of the design decisions that went into Mint and Finch, it&amp;#39;s time to dive into a sample
project. Our sample application will be a functional programming language Hacker News counter. It will work by taking a
Hacker News article ID and then fetching all the child posts of that parent post. It will then leverage a connection
pool to the Hacker News Firebase API to perform a number of concurrent calls to the API to fetch all the child posts.
Once all the child posts have been fetched, all the text bodies will be extracted and analyzed for the names of
certain functional programming languages. Finally, we&amp;#39;ll print out our results, along with some metrics that were
collected via Telemetry events. With all that being said, let&amp;#39;s jump right into it (for reference, all the code can be
found at &lt;a href=&quot;https://github.com/akoutmos/functional_langs&quot;&gt;https://github.com/akoutmos/functional_langs&lt;/a&gt;)!&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s start off by creating a new Elixir project with a supervision tree:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ mix new functional_langs --sup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, let&amp;#39;s open the &lt;code&gt;mix.exs&lt;/code&gt; file and add the required dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:finch, &amp;quot;~&amp;gt; 0.3.0&amp;quot;},
    {:jason, &amp;quot;~&amp;gt; 1.2&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once your &lt;code&gt;mix.exs&lt;/code&gt; file has been updated, switch over to the terminal and run &lt;code&gt;mix deps.get&lt;/code&gt; to fetch your
dependencies. Next, we&amp;#39;ll want to create the file &lt;code&gt;lib/functional_langs/hacker_news_client.ex&lt;/code&gt; that will encompass all of
our Finch related code. This file will include all the calls necessary to interact with the Hacker News Firebase API
and will also include some utility functions to extract the desired data from the JSON payloads. Let&amp;#39;s start off by
adding some of the foundation of our &lt;code&gt;lib/functional_langs/hacker_news_client.ex&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunctionalLangs.HackerNewsClient do
  alias Finch.Response

  def child_spec do
    {Finch,
     name: __MODULE__,
     pools: %{
       &amp;quot;https://hacker-news.firebaseio.com&amp;quot; =&amp;gt; [size: pool_size()]
     }}
  end

  def pool_size, do: 25

  def get_item(item_id) do
    :get
    |&amp;gt; Finch.build(&amp;quot;https://hacker-news.firebaseio.com/v0/item/#{item_id}.json&amp;quot;)
    |&amp;gt; Finch.request(__MODULE__)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our &lt;code&gt;child_spec/0&lt;/code&gt; function defines the child spec for the Finch connection pool. We will be leveraging this function in
our &lt;code&gt;lib/functional_langs/application.ex&lt;/code&gt; file so that we can start up our Finch connection pool within our application
supervision tree. Our &lt;code&gt;pool_size/0&lt;/code&gt; function defines how big our connection pool to the
&lt;code&gt;https://hacker-news.firebaseio.com&lt;/code&gt; address will be. For testing purposes, 25 concurrent connections should be more
than enough to traverse even the largest Hacker News posts. Lastly, the &lt;code&gt;get_item/1&lt;/code&gt; function is what makes the actual
&lt;code&gt;GET&lt;/code&gt; call to the Hacker News Firebase API. We first define the HTTP verb as an atom, we then build the request, and
finally, we make the request while providing the name of the module (notice that this lines up with the name of the
connection pool in &lt;code&gt;child_spec/0&lt;/code&gt;). With that in place, we are able to make calls to the Hacker News Firebase API and
leverage our connection pool using Finch.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;With that in place, let&amp;#39;s wrap up our &lt;code&gt;FunctionalLangs.HackerNewsClient&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunctionalLangs.HackerNewsClient do
  ...

  def get_child_ids(parent_item_id) do
    parent_item_id
    |&amp;gt; get_item()
    |&amp;gt; handle_parent_response()
  end

  defp handle_parent_response({:ok, %Response{body: body}}) do
    child_ids =
      body
      |&amp;gt; Jason.decode!()
      |&amp;gt; Map.get(&amp;quot;kids&amp;quot;)

    {:ok, child_ids}
  end

  def get_child_item(child_id) do
    child_id
    |&amp;gt; get_item()
    |&amp;gt; get_child_item_text()
  end

  defp get_child_item_text({:ok, %Response{body: body}}) do
    body
    |&amp;gt; Jason.decode!()
    |&amp;gt; case do
      %{&amp;quot;text&amp;quot; =&amp;gt; text} -&amp;gt; String.downcase(text)
      _ -&amp;gt; &amp;quot;&amp;quot;
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While the majority of this code snippet is related to unpacking and massaging the data, one thing I&amp;#39;ll touch on though
is the pattern match on the &lt;code&gt;Response&lt;/code&gt; struct. If you recall from the previous code snippet, we &lt;code&gt;alias Finch.Response&lt;/code&gt;
and then use that alias here. By pattern matching on the struct, we are able to easily extract the response body and work
with the returned data. For more details on &lt;code&gt;Finch.Response&lt;/code&gt; struct, feel free to
&lt;a href=&quot;https://hexdocs.pm/finch/Finch.Response.html&quot;&gt;check out the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With our client module wrapped up, let&amp;#39;s quickly open up &lt;code&gt;lib/functional_langs/application.ex&lt;/code&gt; and add the following
line to our supervision tree so that our connection pool can be started with the application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def start(_type, _args) do
  children = [
    FunctionalLangs.HackerNewsClient.child_spec()
  ]

  ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our application will use the Hacker News client that we just wrote to fetch all the child posts of a Hacker News item
and then look for occurrences of functional programming language names in each of those child posts. Once we have
everything tallied up, we&amp;#39;ll present a nice ASCII chart and some overarching metrics. With that said, let&amp;#39;s open up
&lt;code&gt;lib/functional_langs.ex&lt;/code&gt; and start by adding the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunctionalLangs do
  require Logger

  alias FunctionalLangs.HackerNewsClient

  @langs_of_interest ~w(elixir erlang haskell clojure scala f# idris ocaml)
  @label_padding 7
  @telemetry_event_id &amp;quot;finch-timings&amp;quot;

  def generate_report(parent_item_id) do
    # Setup Telemetry events and Agent to store timings
    {:ok, http_timings_agent} = Agent.start_link(fn -&amp;gt; [] end)
    start_time = System.monotonic_time()
    attach_telemetry_event(http_timings_agent)

    # Get all of the child IDs associated with a parent item
    {:ok, child_ids} = HackerNewsClient.get_child_ids(parent_item_id)

    # Concurrently process all of the child IDs and aggregate the results into a graph
    child_ids
    |&amp;gt; Task.async_stream(&amp;amp;HackerNewsClient.get_child_item/1, max_concurrency: HackerNewsClient.pool_size())
    |&amp;gt; Enum.reduce([], fn {:ok, text}, acc -&amp;gt;
      [text | acc]
    end)
    |&amp;gt; Enum.map(&amp;amp;count_lang_occurences/1)
    |&amp;gt; Enum.reduce(%{}, &amp;amp;sum_lang_occurences/2)
    |&amp;gt; print_table_results()

    # Calculate average API request time and total time
    average_time = calc_average_req_time(http_timings_agent)
    total_time = System.convert_time_unit(System.monotonic_time() - start_time, :native, :millisecond)

    # Clean up side-effecty resources
    :ok = Agent.stop(http_timings_agent)
    :ok = :telemetry.detach(@telemetry_event_id)

    IO.puts(&amp;quot;Average request time to Hacker News Firebase API: #{average_time}ms&amp;quot;)
    IO.puts(&amp;quot;Total time to fetch all #{length(child_ids)} child posts: #{total_time}ms&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first few lines of &lt;code&gt;generate_report/1&lt;/code&gt; are responsible for starting an Agent that will be used to collect
Telemetry metrics from Finch. The Agent PID is sent over to the &lt;code&gt;attach_telemetry_event/1&lt;/code&gt; function so that the handler
that is created knows the PID of the Agent. The implementation of the &lt;code&gt;attach_telemetry_event/1&lt;/code&gt; function is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunctionalLangs do
  ...

  defp attach_telemetry_event(http_timings_agent) do
    :telemetry.attach(
      @telemetry_event_id,
      [:finch, :response, :stop],
      fn _event, %{duration: duration}, _metadata, _config -&amp;gt;
        Agent.update(http_timings_agent, fn timings -&amp;gt; [duration | timings] end)
      end,
      nil
    )
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function simply attaches to the Finch &lt;code&gt;[:finch, :response, :stop]&lt;/code&gt; event and adds the duration metric to the
Agent&amp;#39;s list of metrics. Back in our &lt;code&gt;generate_report/1&lt;/code&gt; function, our next step is to get all the child item IDs
from the provided &lt;code&gt;parent_item_id&lt;/code&gt; and put that into our processing pipeline. Our processing pipeline leverages
&lt;code&gt;Task.async_stream/3&lt;/code&gt; in order to concurrently process all the child item IDs. One important thing to note is that
our options to &lt;code&gt;Task.async_stream/3&lt;/code&gt; include &lt;code&gt;max_concurrency: HackerNewsClient.pool_size()&lt;/code&gt;. The reason for this is
that we only want to run the same number of concurrent tasks as there are connections in the Finch connection pool.&lt;/p&gt;
&lt;p&gt;Our next piece of the pipeline is to reduce on the results from &lt;code&gt;Task.async_stream/3&lt;/code&gt; and to extract all the text blocks
that were fetched. Afterward, we perform an &lt;code&gt;Enum.map/2&lt;/code&gt; and an &lt;code&gt;Enum.reduce/3&lt;/code&gt; on those results in order to tally up
our results. The implementations of the functions used in &lt;code&gt;Enum.map/2&lt;/code&gt; and &lt;code&gt;Enum.reduce/3&lt;/code&gt; are:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunctionalLangs do
  ...

  defp count_lang_occurences(text) do
    Map.new(@langs_of_interest, fn string_of_interest -&amp;gt;
      count = if String.contains?(text, string_of_interest), do: 1, else: 0

      {string_of_interest, count}
    end)
  end

  defp sum_lang_occurences(counts, acc) do
    Map.merge(acc, counts, fn _lang, count_1, count_2 -&amp;gt;
      count_1 + count_2
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last step in the pipeline is to take the results and pretty print a sorted ASCII chart so that we can see the
results from greatest to least. Below is the implementation of &lt;code&gt;print_table_results/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunctionalLangs do
  ...

  defp print_table_results(results) do
    results
    |&amp;gt; Enum.sort(fn {_lang_1, count_1}, {_lang_2, count_2} -&amp;gt;
      count_1 &amp;gt; count_2
    end)
    |&amp;gt; Enum.each(fn {language, count} -&amp;gt;
      label = String.pad_trailing(language, @label_padding)
      bars = String.duplicate(&amp;quot;█&amp;quot;, count)

      IO.puts(&amp;quot;#{label} |#{bars}&amp;quot;)
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that completed, all that&amp;#39;s left is to aggregate all the captured Telemetry metrics and compute the average
request time, clean up our side-effecty resources and print the results. The implementation of
&lt;code&gt;calc_average_req_time/1&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunctionalLangs do
  ...

  defp calc_average_req_time(http_timings_agent) do
    http_timings_agent
    |&amp;gt; Agent.get(fn timings -&amp;gt; timings end)
    |&amp;gt; Enum.reduce({0, 0}, fn timing, {sum, count} -&amp;gt;
      {sum + timing, count + 1}
    end)
    |&amp;gt; case do
      {_, 0} -&amp;gt;
        &amp;quot;0&amp;quot;

      {sum, count} -&amp;gt;
        sum
        |&amp;gt; System.convert_time_unit(:native, :millisecond)
        |&amp;gt; Kernel./(count)
        |&amp;gt; :erlang.float_to_binary(decimals: 2)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all that in place, we are ready to use our application! In your terminal, run &lt;code&gt;iex -S mix&lt;/code&gt; to launch an
IEx session with all of our modules loaded. Once your IEx session is up and running, you can call your
&lt;code&gt;FunctionalLangs.generate_report/1&lt;/code&gt; function to generate the language occurrence report (the &amp;quot;23702122&amp;quot; is from the
&amp;quot;July 2020 Who is hiring&amp;quot; post):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1) ▶ FunctionalLangs.generate_report(&amp;quot;23702122&amp;quot;)
scala   |█████████████████████████████████████████████
elixir  |██████████████
clojure |██████████
haskell |█████
f#      |███
erlang  |██
ocaml   |█
idris   |█
Average request time to Hacker News Firebase API: 58.17ms
Total time to fetch all 564 child posts: 2185ms
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks for sticking with me to the end and hopefully you learned a thing or two about Mint and Finch! From this tutorial,
we learned how to create connection pools with Finch, attach Telemetry handlers to Finch events, and how to make large
amounts of concurrent requests to an API. While Finch is relatively new compared to other HTTP clients, it is built upon
tried and tested libraries like Mint and &lt;a href=&quot;https://github.com/dashbitco/nimble_pool&quot;&gt;NimblePool&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building State Machines in Elixir with Ecto </title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/07/14/building-state-machines-in-elixir-with-ecto.html"/>
    <id>https://blog.appsignal.com/2020/07/14/building-state-machines-in-elixir-with-ecto.html</id>
    <published>2020-07-14T00:00:00+00:00</published>
    <updated>2020-07-14T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn when you should use state machines and how to build one with Elixir&#039;s Ecto.</summary>
    <content type="html">&lt;p&gt;Among the many useful patterns in computer science, there is the concept of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Finite-state_machine&quot;&gt;Finite-state machine&lt;/a&gt; (FSM).&lt;/p&gt;
&lt;p&gt;It&amp;#39;s a great abstraction in many different scenarios, where you want to model a certain process that goes through a predefined set of states, with different behaviors, depending on what state it is in.&lt;/p&gt;
&lt;p&gt;In this post, you&amp;#39;ll learn how to implement this pattern with Elixir&amp;#39;s Ecto and when to use it.&lt;/p&gt;
&lt;h2&gt;Use Cases&lt;/h2&gt;
&lt;p&gt;When you model a long-running flow that requires multiple steps, and where each step has different
requirements, a state machine can be a good choice as an abstraction. A few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A user onboarding flow where the user first signs up, then adds some extra required info, confirms his email, then enables 2FA, and only then is allowed into the system&lt;/li&gt;
&lt;li&gt;A shopping cart which starts out empty, allows products to be added indefinitely and can proceed to payment/shipping if enough products are added&lt;/li&gt;
&lt;li&gt;A task in a project management pipeline. e.g: Tasks start out in the backlog, can be assigned to people, moved to &amp;quot;in progress&amp;quot;, and later to &amp;quot;done&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;An Example of a Finite-State Machine&lt;/h2&gt;
&lt;p&gt;For this post, we&amp;#39;ll stick with a small example that illustrates the flow of a state machine: A door.&lt;/p&gt;
&lt;p&gt;A door can be locked or unlocked. It can also be opened or closed. While unlocked, it can also be opened.&lt;/p&gt;
&lt;p&gt;We could model this as a finite-state machine, such as the following:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-07/fsm.png&quot; alt=&quot;FSM&quot;/&gt;&lt;/p&gt;
&lt;p&gt;This FSM has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3 possible states: Locked, Unlocked, Opened&lt;/li&gt;
&lt;li&gt;4 possible transitions or events: Unlock, Open, Close, Lock&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It can be inferred from the diagram that it&amp;#39;s impossible to transition from &lt;code&gt;Locked&lt;/code&gt; to &lt;code&gt;Opened&lt;/code&gt;. Or in plain words: you need to
unlock the door first.
The state machine diagram describes the behavior. But how can we go about implementing it?&lt;/p&gt;
&lt;h2&gt;State Machines as Elixir Processes&lt;/h2&gt;
&lt;p&gt;Since OTP 19, Erlang provides a &lt;code&gt;:gen_statem&lt;/code&gt; module that allows implementing gen_server-like processes that behave as state machines (where the current state influences their behavior). Let&amp;#39;s see what that would look like for our door
example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Door do
  @behaviour :gen_statem

  def start_link do
    :gen_statem.start_link( __MODULE__,:ok,[] )
  end

  @impl :gen_statem
  def init(_), do: {:ok, :locked, nil}

  @impl :gen_statem
  def callback_mode, do: :handle_event_function

  @impl :gen_statem
  def handle_event({:call, from}, :unlock, :locked, data) do
    {:next_state, :unlocked, data, [{:reply, from, {:ok, :unlocked}}]}
  end

  def handle_event({:call, from}, :lock, :unlocked, data) do
    {:next_state, :locked, data, [{:reply, from, {:ok, :locked}}]}
  end

  def handle_event({:call, from}, :open, :unlocked, data) do
    {:next_state, :opened, data, [{:reply, from, {:ok, :opened}}]}
  end

  def handle_event({:call, from}, :close, :opened, data) do
    {:next_state, :unlocked, data, [{:reply, from, {:ok, :unlocked}}]}
  end

  def handle_event({:call, from}, _event, _content, data) do
    {:keep_state, data, [{:reply, from, {:error, &amp;quot;invalid transition&amp;quot;}}]}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;This implements a process that starts out in the &lt;code&gt;:locked&lt;/code&gt; state. By sending appropriate events, we are able to match
the current state with the transition requested and perform the required transformations. An additional &lt;code&gt;data&lt;/code&gt; argument
is kept for any additional state that is needed, but we&amp;#39;re not using that in this case.&lt;/p&gt;
&lt;p&gt;To use this process, you can call it with the desired transition that you want to execute. If the current state allows that
transition, it will work. Otherwise, an error is returned (due to the last, catch-all match of the code snippet).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:ok, pid} = Door.start_link()

:gen_statem.call(pid, :unlock)
# {:ok, :unlocked}

:gen_statem.call(pid, :open)
# {:ok, :opened}

:gen_statem.call(pid, :close)
# {:ok, :closed}

:gen_statem.call(pid, :lock)
# {:ok, :locked}

:gen_statem.call(pid, :open)
# {:error, &amp;quot;invalid transition&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If our state machine is more data-oriented than process-oriented, we may want to go with a different
approach...&lt;/p&gt;
&lt;h2&gt;State Machines as Ecto Models&lt;/h2&gt;
&lt;p&gt;There are a couple of Elixir packages that deal with this problem. For this post, I&amp;#39;ll be using
&lt;a href=&quot;https://github.com/subvisual/fsmx&quot;&gt;&lt;code&gt;fsmx&lt;/code&gt;&lt;/a&gt;, but other packages such as &lt;a href=&quot;https://github.com/joaomdmoura/machinery&quot;&gt;&lt;code&gt;machinery&lt;/code&gt;&lt;/a&gt; also provide similar features.&lt;/p&gt;
&lt;p&gt;This package allows us to model the same kind of states and transitions within an existing Ecto Model:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule PersistedDoor do
  use Ecto.Schema

  schema &amp;quot;doors&amp;quot; do
    field :state, :string, default: &amp;quot;locked&amp;quot;
    field :terms_and_conditions, :boolean
  end

  use Fsmx.Struct, transitions: %{
    &amp;quot;locked&amp;quot; =&amp;gt; &amp;quot;unlocked&amp;quot;,
    &amp;quot;unlocked&amp;quot; =&amp;gt; [&amp;quot;locked&amp;quot;, &amp;quot;opened&amp;quot;],
    &amp;quot;opened&amp;quot; =&amp;gt; &amp;quot;unlocked&amp;quot;
  }
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that &lt;code&gt;Fsmx.Struct&lt;/code&gt; receives all possible transitions as an argument. This allows it to check for unwanted
transitions and prevent them from happening. Now, we can transition using a traditional, non-Ecto approach:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;door = %PersistedDoor{state: &amp;quot;locked&amp;quot;}

Fsmx.transition(door, &amp;quot;unlocked&amp;quot;)
# {:ok, %PersistedDoor{state: &amp;quot;unlocked&amp;quot;, color: nil}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we can also ask for the same in the form of an Ecto changeset:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# get an existing door from the Database
door = PersistedDoor |&amp;gt; Repo.one()

Fsmx.transition_changeset(door, &amp;quot;unlocked&amp;quot;)
|&amp;gt; Repo.update()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This changeset only updates the &lt;code&gt;:state&lt;/code&gt; field. But we can extend it to include additional fields, as well as
validations. Let&amp;#39;s say that, in order to open a door, we need to accept its terms &amp;amp; conditions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule PersistedDoor do
  # ...

  def transition(changeset, _from, &amp;quot;opened&amp;quot;, params) do
    changeset
    |&amp;gt; cast(params, [:terms_and_conditions])
    |&amp;gt; validate_acceptance(:terms_and_conditions)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Fsmx&lt;/code&gt; looks for an optional &lt;code&gt;transition_changeset/4&lt;/code&gt; function in your schema and calls it with the previous state as
well as the next one. You can pattern match on those to add specific conditions for each transition.&lt;/p&gt;
&lt;h2&gt;Dealing With Side Effects&lt;/h2&gt;
&lt;p&gt;It&amp;#39;s one thing to transition the state machine itself and move forward with the state.
But another big benefit of state machines is the ability to deal with particular side effects that come out of each
state.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say, for example, you want to get notified every time someone unlocks your door. You might want to trigger an email
when it happens. But you want these two operations to be a single, atomic operation.&lt;/p&gt;
&lt;p&gt;Ecto deals with atomicity via &lt;code&gt;Ecto.Multi&lt;/code&gt; which groups multiple operations inside a database transaction. It also has
an &lt;code&gt;Ecto.Multi.run/3&lt;/code&gt; function that allows you to run arbitrary code within that same transaction.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Fsmx&lt;/code&gt; in turn, integrates with &lt;code&gt;Ecto.Multi&lt;/code&gt; by providing you with a way to run state transitions as part of an
&lt;code&gt;Ecto.Multi&lt;/code&gt;, while also providing you an additional callback that is executed in that case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule PersistedDoor do
  # ...

  def after_transaction_multi(changeset, _from, &amp;quot;unlocked&amp;quot;, params) do
    Emails.door_unlocked()
    |&amp;gt; Mailer.deliver_later()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you can execute a transition as shown:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;door = PersistedDoor |&amp;gt; Repo.one()

Ecto.Multi.new()
|&amp;gt; Fsmx.transition_multi(schema, &amp;quot;transition-id&amp;quot;, &amp;quot;unlocked&amp;quot;)
|&amp;gt; Repo.transaction()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This transaction will use the same &lt;code&gt;transition_changeset/4&lt;/code&gt; from above to compute the necessary changes to the model
and will include the new callback as an &lt;code&gt;Ecto.Multi.run&lt;/code&gt; call. The result is that an email is sent (asynchronously,
using &lt;a href=&quot;https://github.com/thoughtbot/bamboo&quot;&gt;&lt;code&gt;Bamboo&lt;/code&gt;&lt;/a&gt;, so as not to run within the transaction itself). If the
changeset is invalidated for some reason, the email ends up never being sent, resulting in an atomic execution of both
operations.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Next time you&amp;#39;re modeling some kind of stateful behavior, consider looking into a state-machine approach. Regardless of
which flavor you use, the ability to translate a concrete diagram to actual code and the ability to test each state,
transition, and side effect as a separate piece is a huge advantage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Best Practices for Background Jobs in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/06/24/best-practices-for-background-jobs-in-elixir.html"/>
    <id>https://blog.appsignal.com/2020/06/24/best-practices-for-background-jobs-in-elixir.html</id>
    <published>2020-06-24T00:00:00+00:00</published>
    <updated>2020-06-24T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn how to avoid some common mistakes while working with background jobs in Elixir.</summary>
    <content type="html">&lt;p&gt;Erlang &amp;amp; Elixir are ready for asynchronous work right off the bat. Generally speaking, background job systems aren&amp;#39;t
needed as much as in other ecosystems but they still have their place for particular use cases.&lt;/p&gt;
&lt;p&gt;This post goes through a few best practices I often try to think of in advance when writing background jobs, so that I don&amp;#39;t hit some of the pain points that have hurt me multiple times in the past.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;ve ever deployed a new task, only to find out that it has gone rogue with a bug that caused it to misbehave
(e.g.: sending way too many emails, way too quickly), you may have gone through similar bugs as well.&lt;/p&gt;
&lt;h2&gt;Flavours&lt;/h2&gt;
&lt;p&gt;Elixir already gives you the ability to schedule asynchronous work pretty easily. Something as simple as this already
covers a lot:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Task.async(fn -&amp;gt;
  # some heavy lifting
end)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might need something a bit more powerful, either just for convenience (having some tooling &amp;amp; monitoring around
that task), or because you need something like periodic jobs. Again, all this can be achieved with something like
a GenServer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule PeriodicJob do
  use GenServer

  @period 60_000

  def init do
    Process.send_after(self(), :poll, @period)

    {:ok, :state}
  end

  def handle_info(:poll, state) do
    # some heavy lifting

    Process.send_after(self(), :poll, @period)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also use a job queuing library such as &lt;a href=&quot;https://github.com/quantum-elixir/quantum-core&quot;&gt;&lt;code&gt;Quantum&lt;/code&gt;&lt;/a&gt;. If you come from Ruby land and are used to libraries such as
&lt;a href=&quot;https://github.com/mperham/sidekiq&quot;&gt;&lt;code&gt;Sidekiq&lt;/code&gt;&lt;/a&gt;, you might be more familiar with something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#
# lib/my_app/scheduler.ex
#
defmodule MyApp.Scheduler do
  use Quantum.Scheduler, opt_app: :my_app
end

#
# config/config.exs
#
config :my_app, MyApp.Scheduler,
  jobs: [
    first: [
      # every hour
      schedule: &amp;quot;0 * * * *&amp;quot;,
      task: {MyApp.ExampleJob, :run, []}
    ],
    second: [
      # every minute
      schedule: &amp;quot;* * * * *&amp;quot;,
      task: {MyApp.AnotherExampleJob, :run, []}
    ]
  ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some may argue that since Erlang/OTP already provides the infrastructure for creating these processes, packages such
as &lt;code&gt;Quantum&lt;/code&gt; are not necessary. However, the structure created by them can end up being more intuitive, especially if you&amp;#39;re
not that familiar with OTP. This might be the case with someone coming from Ruby or other such communities.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;How to Structure Background Jobs&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s now get into a few tips that will help you keep your jobs ready to deal with potential future problems!&lt;/p&gt;
&lt;p&gt;Most of them are preventive measures due to the fact that all of these are background processes. They&amp;#39;re not responding
to an HTTP request and they happen without any intervention, thus sometimes, debugging can be hard if you don&amp;#39;t take some
precautions.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s consider a small example that sends confirmation emails to users that haven&amp;#39;t received it yet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.ExampleJob do
  def run do
    get_users()
    |&amp;gt; Enum.each(fn user -&amp;gt;
      # send single email to user
    end)
  end

  defp get_users do
    MyApp.User
    |&amp;gt; where(confirmation_email_sent: false)
    |&amp;gt; MyApp.Repo.all()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;1. Put in a Kill Switch&lt;/h3&gt;
&lt;p&gt;This is one of those mistakes I&amp;#39;ll never make again since it has hurt me so many times.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s say you&amp;#39;ve created a background job, tested, deployed, and configured it to run periodically and send some emails.&lt;/p&gt;
&lt;p&gt;It hits production, and you soon notice that something&amp;#39;s wrong. The same 100 people are being spammed with emails every
minute. You messed up the &lt;code&gt;geth_next_batch/1&lt;/code&gt; function, and it always goes over the same batch of users.
It&amp;#39;s a developer&amp;#39;s horror story. You need to fix it (or kill it) quickly, but all that time waiting for a new release to get
online is physically painful.&lt;/p&gt;
&lt;p&gt;So, avoid that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.ExampleJob do
  def run do
    return if !enabled?

    # ...
  end

  defp enabled? do
    # check a Redis flag, or a database record, or anything really
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can plug in some persistent system that allows you to quickly toggle the job on/off. A good suggestion would be to
use a feature flag package, such as &lt;a href=&quot;https://github.com/tompave/fun_with_flags&quot;&gt;FunWithFlags&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;2. Always Batch Your Jobs by Default&lt;/h3&gt;
&lt;p&gt;It&amp;#39;s easy to miss this one on a first draft. You&amp;#39;re just trying to quickly get something online.
But in some cases, it may be important to not hurt your performance if you&amp;#39;re working on a very resource-intensive job,
or simply, if your list of records to process grows too quickly.&lt;/p&gt;
&lt;p&gt;Doing &lt;code&gt;User |&amp;gt; where(confirmation_email_sent: false) |&amp;gt; Repo.all()&lt;/code&gt; can be dangerous if there&amp;#39;s potential for that to
yield too many results.
You may end up consuming too many resources for something that could be done in smaller batches, keeping your system
a lot more stable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.ExampleJob do
  @batch_size 100

  defp get_users do
    MyApp.User
    |&amp;gt; where(confirmation_email_sent: false)
    |&amp;gt; limit(^@batch_size)
    |&amp;gt; MyApp.Repo.all()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whatever job queue mechanism you plug this worker into, it will end up being called frequently. So you shouldn&amp;#39;t hurry
in processing smaller batches one at a time.&lt;/p&gt;
&lt;h3&gt;3. Avoid Overlaps&lt;/h3&gt;
&lt;p&gt;This is kind of related to the previous point, but it&amp;#39;s a concern that goes beyond performance.&lt;/p&gt;
&lt;p&gt;If you program a job to run every minute, and a single execution has the potential to last longer than that, you end up
risking cascading performance problems, or even worse, race conditions, where the first and second executions are both
trying to process the same set of data, and conflict with each other in the process.&lt;/p&gt;
&lt;p&gt;This is obviously dependent on what your exact business logic is, but as a general rule, it&amp;#39;s best to be defensive here.&lt;/p&gt;
&lt;p&gt;If you use a GenServer approach like the one showcased above, this is solved automatically, as instead of scheduling
jobs every minute, you can instead use &lt;code&gt;Process.send_after(self(), :poll, delay)&lt;/code&gt; to only schedule the next run after
the current one has finished, avoiding overlap.&lt;/p&gt;
&lt;p&gt;When using &lt;code&gt;Quantum&lt;/code&gt;, you also have an &lt;code&gt;overlap: true&lt;/code&gt; option that you can add to automatically prevent this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config :my_app, MyApp.Scheduler,
  jobs: [
    first: [
      # every hour
      schedule: &amp;quot;0 * * * *&amp;quot;,
      task: {MyApp.ExampleJob, :run, []}
      overlap: false
    ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This, by the way, might already be reason enough to consider using a package rather than just plain Elixir.&lt;/p&gt;
&lt;h3&gt;4. Plug in a Manual Mode&lt;/h3&gt;
&lt;p&gt;If your job is processing a batch of records, it&amp;#39;s useful to plug in some public functions that allow you to manually
process specific records. This can serve two purposes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better ability to debug the job&lt;/li&gt;
&lt;li&gt;Ability to do a few manual runs before enabling the global job (by toggling the feature flag discussed above)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A sample structure could look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.ExampleJob do
  import MyApp.Lock

  def run do
    lock(&amp;quot;example_job&amp;quot;, fn -&amp;gt;
      get_users()
      |&amp;gt; Enum.each(&amp;amp;process_user/1)
    end)
  end

  def run_manually(users) when is_list(users) do
    lock(&amp;quot;example_job&amp;quot;, fn -&amp;gt;
      users
      |&amp;gt; Enum.each(&amp;amp;process_user/1)
    end)
  end

  def run_manually(user), do: run_manually([user])

  def process_user(%User{} = user) do
    # process a single user
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, we&amp;#39;re creating a &lt;code&gt;run_manually/1&lt;/code&gt; public function that can receive either a single user or a batch of
them and performs the same logic as the automatic job would.&lt;/p&gt;
&lt;p&gt;One important detail here is to again avoid a race condition, which in this case, is being done with a custom &lt;code&gt;Lock&lt;/code&gt;
module that uses the &lt;a href=&quot;https://github.com/queer/redis_mutex&quot;&gt;&lt;code&gt;redis_mutex&lt;/code&gt;&lt;/a&gt; package to prevent potential issues:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Lock do
  use RedisMutex
  require Logger

  def lock(lock_name, fun) do
    with_lock(lock_name, 60_000) do
      fun.()
    end
  rescue
    _e in RedisMutex.Error -&amp;gt;
      Logger.debug(&amp;quot;#{locker_name} another process already running&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lock, which is invoked both on manual runs as well as the regular background job, ensures that you won&amp;#39;t cause any
unintentional conflicts if you try to do a manual run at the same time the job is doing the same processing. It also
happens to solve the overlap problem discussed previously in this post.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;All these tips come from something that I bumped into in the past, usually related to production bugs or user
complaints. So I hope some of them help you avoid the same mistakes. Let me know if you
have any further thoughts! 👋&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Using Mnesia in an Elixir Application</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/05/19/using-mnesia-in-an-elixir-application.html"/>
    <id>https://blog.appsignal.com/2020/05/19/using-mnesia-in-an-elixir-application.html</id>
    <published>2020-05-19T00:00:00+00:00</published>
    <updated>2020-05-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn about Mnesia and how to use it in an Elixir application.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This post was updated on 9 August 2023 with some minor code changes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In today&amp;#39;s post, we&amp;#39;ll learn about Mnesia, see when you would use such a tool, and take a look at some
of the pros and cons of using it. After covering the fundamentals of Mnesia, we&amp;#39;ll dive right into a sample
application where we&amp;#39;ll build an Elixir application that uses Mnesia as its database. Let&amp;#39;s jump right in!&lt;/p&gt;
&lt;h2&gt;Introduction to Mnesia&lt;/h2&gt;
&lt;p&gt;At a high level, &lt;a href=&quot;https://www.erlang.org/doc/man/mnesia.html&quot;&gt;Mnesia&lt;/a&gt; is a Database Management System (DBMS) that is baked into OTP. Thus, if you are
using Elixir or Erlang, you have the ability to leverage Mnesia out-of-the-box. No additional dependencies need to be
installed and no separate systems need to be running. Before considering migrating everything from your existing
database to Mnesia, let&amp;#39;s discuss what Mnesia was designed for and what problems it aims to solve.&lt;/p&gt;
&lt;p&gt;Mnesia was largely designed to solve the problems that existed in the telecommunications problem space. Specifically,
some of the following requirements needed to be fulfilled:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fast key/value lookup times where you need soft real-time latency guarantees. A soft real-time system is one where the
system should be able to service the majority of its requests within a given time frame and a failure to do so
generally means degradation of service (i.e the data is no longer useful after the time frame has passed). A hard
real-time system, on the other hand, is a system that &lt;em&gt;must&lt;/em&gt; respond within a given time frame or else it is considered
a system failure.&lt;/li&gt;
&lt;li&gt;The ability to perform complex queries (like you would in SQL for example), but without soft real-time latency
guarantees&lt;/li&gt;
&lt;li&gt;A high level of fault tolerance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In a typical DBMS, your application would need to either make a network call to a separate machine where the database is
running, or it would have to connect to the database process that is running on the same machine. Either way, the data
that is contained within that database resides in an entirely separate memory space than the application, and therefore,
there is an inescapable amount of latency overhead.&lt;/p&gt;
&lt;p&gt;On the other hand, Mnesia runs within the same memory space as the
application. As a result of being baked into the language and runtime, you are able to fetch data out of Mnesia at soft
real-time speeds. In other words, your application and database are running side-by-side and there is little to no
communication overhead between the two.&lt;/p&gt;
&lt;p&gt;Another important thing to note is that Mnesia stores all of the Erlang data
types natively, and so there is no need to marshall/unmarshall data when you read/write to Mnesia (marshalling is the
process of converting data from one format to another for the purposes of storing it or transmitting it).&lt;/p&gt;
&lt;p&gt;When performing complex queries against your Mnesia database, you can either leverage &lt;a href=&quot;https://erlang.org/doc/man/qlc.html&quot;&gt;Query List Comprehensions&lt;/a&gt; (QLC) or you can write &lt;a href=&quot;http://erlang.org/doc//apps/erts/match_spec.html&quot;&gt;Match Specifications&lt;/a&gt;. In addition, you can also add indexes to your Mnesia tables
for fields that you know you&amp;#39;ll be querying often. Using these tools, you can perform arbitrary queries against your
tables and extract the relevant data.&lt;/p&gt;
&lt;p&gt;A primary requirement of telecommunications systems is that they must be running nonstop. Downtime means missed or
dropped calls. Mnesia addresses this by allowing tables to be replicated across the various nodes in the cluster.&lt;/p&gt;
&lt;p&gt;When running within a transaction, the data that needs to be committed must be written to all the configured table
replicas. If nodes are unavailable during a write, the transaction will update the available node replicas and will
update the unavailable node replicas when they come back online. Through this replication mechanism, Mnesia is able to
provide a high level of fault tolerance.&lt;/p&gt;
&lt;h2&gt;Mnesia and the CAP Theorem&lt;/h2&gt;
&lt;p&gt;You may be wondering exactly where it falls in regards to the CAP theorem. For those unfamiliar with the CAP theorem, it
basically states that, when dealing with distributed systems, you have three characteristics at play but can only
guarantee two at any given time. Those three characteristics are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistency: Whenever a read is made against your database, the database will respond with the most recently updated
data.&lt;/li&gt;
&lt;li&gt;Availability: Whenever a request is made against your database, the database will respond with some data even if it&amp;#39;s out of date (i.e. newer data has been committed but has not propagated to all nodes).&lt;/li&gt;
&lt;li&gt;Partition tolerance: Whenever a request is made against your database, it will be able to respond regardless of some
nodes being unavailable.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When a network partition does occur (i.e. some database nodes are unavailable), your system must make a trade-off. Does
it favor consistency and error out on any requests while some nodes are unavailable, or does it favor availability by
servicing the request with the understanding that there may be some data inconsistency when the missing nodes come back
online?&lt;/p&gt;
&lt;p&gt;Given that Mnesia will propagate transaction commits across all table replicas and does not support any kind of eventual
consistency, it is more of a CP style database. In the case of a network partition where the separate partitions are
both handling requests, the application will need to deal with reconciliation of the data.&lt;/p&gt;
&lt;h2&gt;When To Use Mnesia Over PostgreSQL or Other Database&lt;/h2&gt;
&lt;p&gt;Like many things in Software Engineering and Systems Design, it&amp;#39;s all about making the correct trade-offs. Whether
Mnesia is right or not for your application largely depends on its requirements. Personally, I
have used Mnesia in production primarily to support some soft real-time use cases with very good results.&lt;/p&gt;
&lt;p&gt;The data that
was stored in Mnesia was needed only for the duration of the user&amp;#39;s session and would then get cleared after the user&amp;#39;s
interaction with the system ceased. Thus, there wasn&amp;#39;t a lot of pressure on system resources (RAM specifically, as
the tables need to fit into RAM), as the size of the tables would reflect the number of users actively using the system.
For situations where you need to store a large amount of data and you do not require soft real-time response times, a
traditional DBMS such as MySQL or Postgres may be a better choice.&lt;/p&gt;
&lt;p&gt;For situations where you see yourself reaching for
Redis or Memcached, you may want to consider looking into Mnesia, given that it fills a similar need and is built into
OTP. For more information regarding this topic, I would suggest &lt;a href=&quot;https://erlang.org/doc/apps/mnesia/Mnesia_overview.html#when-to-use-mnesia&quot;&gt;looking at Mnesia docs&lt;/a&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Hands-on Project with Mnesia&lt;/h2&gt;
&lt;p&gt;In order to get familiar with Mnesia, we&amp;#39;ll be creating a very simple banking application that leverages Mnesia as its
database. While we could leverage the Mnesia API directly via &lt;code&gt;:mnesia&lt;/code&gt;, we will instead opt to use the &lt;a href=&quot;https://github.com/meh/amnesia&quot;&gt;Amnesia library&lt;/a&gt; as it provides a nice Elixir wrapper around the Mnesia API. Our banking application will support the following
operations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create new accounts&lt;/li&gt;
&lt;li&gt;Transfer money between accounts&lt;/li&gt;
&lt;li&gt;Fetch account details&lt;/li&gt;
&lt;li&gt;Deposit funds into an account&lt;/li&gt;
&lt;li&gt;Withdraw funds from an account&lt;/li&gt;
&lt;li&gt;Search for accounts with a low balance&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#39;s create a new Elixir project using the following terminal command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ mix new fort_knox --sup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Quick tip: The &lt;code&gt;--sup&lt;/code&gt; flag adds a &lt;a href=&quot;https://hexdocs.pm/mix/1.14/Mix.Tasks.New.html&quot;&gt;supervision tree&lt;/a&gt; to the app.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After creating the Elixir project, open up the &lt;code&gt;mix.exs&lt;/code&gt; file and add &lt;code&gt;amnesia&lt;/code&gt; to it as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:amnesia, &amp;quot;~&amp;gt; 0.2.8&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that has been done, you can run &lt;code&gt;mix deps.get&lt;/code&gt; to fetch the &lt;code&gt;amnesia&lt;/code&gt; dependency. Next, we&amp;#39;ll want to create a
module that defines all the table schemas in our Mnesia database. For our sample application, we will only have one table
defined for bank accounts. To do this, add the following content to &lt;code&gt;lib/database.ex&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;use Amnesia

defdatabase Database do
  deftable(
    Account,
    [{:id, autoincrement}, :first_name, :last_name, :balance],
    type: :ordered_set,
    index: [:balance]
  )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our database contains only the &lt;code&gt;Account&lt;/code&gt; table and specifies that it has 3 fields along with an auto-incrementing &lt;code&gt;id&lt;/code&gt;
field. With the database definition in place, let&amp;#39;s go back to our terminal and run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ mix amnesia.create -d Database --disk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After executing that command, you will notice that a new directory (&lt;code&gt;Mnesia.nonode@nohost&lt;/code&gt;) has been created for us at the root of
our project. This directory contains all the disk persisted data so that our data can be maintained across application
restarts. To delete all of the persisted database data, you can either &lt;code&gt;rm -rf Mnesia.nonode@nohost&lt;/code&gt; or run
&lt;code&gt;mix amnesia.drop -d Database --schema&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that in place, it&amp;#39;s time to work on some of our business logic. Let&amp;#39;s create a file at &lt;code&gt;lib/fort_knox/accounts.ex&lt;/code&gt;
and start off by creating functions that will create a new account and fetch existing accounts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/fort_knox/accounts.ex

defmodule FortKnox.Accounts do
  require Amnesia
  require Amnesia.Helper
  require Exquisite
  require Database.Account

  alias Database.Account

  def create_account(first_name, last_name, starting_balance) do
    Amnesia.transaction do
      %Account{first_name: first_name, last_name: last_name, balance: starting_balance}
      |&amp;gt; Account.write()
    end
  end

  def get_account(account_id) do
    Amnesia.transaction do
      Account.read(account_id)
    end
    |&amp;gt; case do
      %Account{} = account -&amp;gt; account
      _ -&amp;gt; {:error, :not_found}
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our module begins with a few &lt;code&gt;require&lt;/code&gt; statements to pull in Amnesia functionality. We can then leverage &lt;code&gt;Account&lt;/code&gt; as a
struct to conveniently interact with the &lt;code&gt;Account&lt;/code&gt; table in Mnesia. To create a new &lt;code&gt;Account&lt;/code&gt; entry in the table, we
create the struct and call &lt;code&gt;Account.write()&lt;/code&gt; within a transaction. If you do not want to perform your database actions
within a transaction, you can also leverage the dirty read/write API calls, but that is not recommended. When looking up
existing accounts by their id, we once again leverage a transaction and match on an &lt;code&gt;Account&lt;/code&gt; struct if an account was
found. Let&amp;#39;s go ahead and add the remainder of our functionality in &lt;code&gt;lib/fort_knox/accounts.ex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/fort_knox/accounts.ex

defmodule FortKnox.Accounts do
  ...

  def transfer_funds(source_account_id, destination_account_id, amount) do
    Amnesia.transaction do
      accounts = {Account.read(source_account_id), Account.read(destination_account_id)}

      case accounts do
        {%Account{} = source_account, %Account{} = destination_account} -&amp;gt;
          if amount &amp;lt;= source_account.balance do
            adjust_account_balance(destination_account, amount)
            adjust_account_balance(source_account, -amount)
            :ok
          else
            {:error, :insufficient_funds}
          end

        {%Account{}, _} -&amp;gt;
          {:error, :invalid_destination}

        {_, _} -&amp;gt;
          {:error, :invalid_source}
      end
    end
  end

  def get_low_balance_accounts(min_balance) do
    Amnesia.transaction do
      Account.where(balance &amp;lt; min_balance)
      |&amp;gt; Amnesia.Selection.values()
    end
  end

  def deposit_funds(account_id, amount) do
    Amnesia.transaction do
      case Account.read(account_id) do
        %Account{} = account -&amp;gt;
          adjust_account_balance(account, amount)

        _ -&amp;gt;
          {:error, :not_found}
      end
    end
  end

  def withdraw_funds(account_id, amount) do
    Amnesia.transaction do
      case Account.read(account_id) do
        %Account{} = account -&amp;gt;
          if amount &amp;lt;= account.balance do
            adjust_account_balance(account, -amount)
          else
            {:error, :insufficient_funds}
          end

        _ -&amp;gt;
          {:error, :not_found}
      end
    end
  end

  defp adjust_account_balance(%Account{} = account, amount) do
    account
    |&amp;gt; Map.update!(:balance, &amp;amp;(&amp;amp;1 + amount))
    |&amp;gt; Account.write()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;withdraw_funds/2&lt;/code&gt;, &lt;code&gt;deposit_funds/2&lt;/code&gt; and &lt;code&gt;transfer_funds/3&lt;/code&gt; functions should be relatively straight forward as they
are a mixture of reads and writes to update accounts within a transaction. The &lt;code&gt;get_low_balance_accounts/1&lt;/code&gt; will
probably seem new as we have a &lt;code&gt;where&lt;/code&gt; clause to query our database records. The &lt;a href=&quot;https://github.com/meh/exquisite&quot;&gt;Exquisite library&lt;/a&gt; (which Amnesia depends
on) provides the ability to generate Mnesia Match Specifications which are used to perform custom queries [5].&lt;/p&gt;
&lt;p&gt;With all that in place, let&amp;#39;s take this all for a test drive. We&amp;#39;ll first seed our database with some initial accounts
and then transfer some funds between the accounts. Open up an IEx session via &lt;code&gt;iex -S mix&lt;/code&gt; and type the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;iex(1) ▶ [
...(1) ▶ {&amp;quot;Josh&amp;quot;, &amp;quot;Smith&amp;quot;, 1_000},
...(1) ▶ {&amp;quot;Tom&amp;quot;, &amp;quot;Lee&amp;quot;, 500},
...(1) ▶ {&amp;quot;Joe&amp;quot;, &amp;quot;Diaz&amp;quot;, 1_500}
...(1) ▶ ] |&amp;gt;
...(1) ▶ Enum.each(fn {first_name, last_name, amount} -&amp;gt;
...(1) ▶ FortKnox.Accounts.create_account(first_name, last_name, amount)
...(1) ▶ end)
:ok

iex(2) ▶ FortKnox.Accounts.get_account(1)
%Database.Account{balance: 1000, first_name: &amp;quot;Josh&amp;quot;, id: 1, last_name: &amp;quot;Smith&amp;quot;}

iex(3) ▶ FortKnox.Accounts.get_account(2)
%Database.Account{balance: 500, first_name: &amp;quot;Tom&amp;quot;, id: 2, last_name: &amp;quot;Lee&amp;quot;}

iex(4) ▶ FortKnox.Accounts.transfer_funds(2, 1, 400)
:ok

iex(5) ▶ FortKnox.Accounts.get_account(1)
%Database.Account{balance: 1400, first_name: &amp;quot;Josh&amp;quot;, id: 1, last_name: &amp;quot;Smith&amp;quot;}

iex(6) ▶ FortKnox.Accounts.get_account(2)
%Database.Account{balance: 100, first_name: &amp;quot;Tom&amp;quot;, id: 2, last_name: &amp;quot;Lee&amp;quot;}

iex(7) ▶ FortKnox.Accounts.get_low_balance_accounts(250)
[%Database.Account{balance: 100, first_name: &amp;quot;Tom&amp;quot;, id: 2, last_name: &amp;quot;Lee&amp;quot;}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After running all of these commands, feel free to quit from IEx via Ctrl+C and go back to using &lt;code&gt;iex -S mix&lt;/code&gt;. If you run
&lt;code&gt;Database.Account.count()&lt;/code&gt;, you&amp;#39;ll see that we get a value of 3 since our data persisted across IEx sessions and was not
destroyed.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks for sticking with me to the end and hopefully you learned a thing or two about Mnesia and how to go about using
it within an Elixir application. Regardless of whether you decide to use Mnesia in a production context or not, I would
highly suggest at least experimenting with it so as to better appreciate the amazing things that you get out-of-the-box
with OTP.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Configuring your Elixir Application at Runtime with Vapor</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/04/28/configuring-your-elixir-application-at-runtime-with-vapor.html"/>
    <id>https://blog.appsignal.com/2020/04/28/configuring-your-elixir-application-at-runtime-with-vapor.html</id>
    <published>2020-04-28T00:00:00+00:00</published>
    <updated>2020-04-28T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn how to configure your application with Vapor in a safe, consistent, and reliable way that will last you well into the future.</summary>
    <content type="html">&lt;p&gt;Configuration has long been a hot topic in the Elixir community, and luckily, in the recent months, there has been a
great deal of thoughtful work put into making this problem an easier one to solve. Today, we&amp;#39;re going to show you how to migrate from an Elixir application that has been configured
with the widely used &lt;code&gt;config/*.exs&lt;/code&gt; files at compile-time, to an application that instead uses
environment variables for configuration and is configured at runtime.&lt;/p&gt;
&lt;p&gt;But, before we get into the details of some of the recent and upcoming changes happening in
this area, let&amp;#39;s just go over some of the historical problems that came from the way Elixir applications
were configured in the past.&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s Wrong with &lt;code&gt;config.exs&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;Well, for some applications, nothing. But there is an increasing number of teams
that have encountered issues around the configuration of their applications as they become larger,
and especially, as their deployment strategy changes. As someone who has spent the majority of the
last 4 years as a freelancer working on several different Elixir applications, I can say that I&amp;#39;ve
personally seen issues on every project I&amp;#39;ve worked on in that time, except for one (and that one
was a greenfield project that was designed to be configured in the way we&amp;#39;ll be discussing
today). Some of the most common configuration related issues that the community has been seeing
are:&lt;/p&gt;
&lt;h3&gt;Confusing Runtime vs. Compile-time Configuration&lt;/h3&gt;
&lt;p&gt;If you are compiling and deploying &lt;a href=&quot;https://elixir-lang.org/getting-started/mix-otp/config-and-releases.html#releases&quot;&gt;OTP releases&lt;/a&gt;
for your application, I have a suspicion that you&amp;#39;ve run into at least one case where you were
confused by an environment variable shown as &amp;quot;missing&amp;quot; in production even though you were
&lt;strong&gt;sure&lt;/strong&gt; it had been set. The code around this might have looked something like this (in
&lt;code&gt;config/config.exs&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :my_app, MyApp.Repo,
  url: System.get_env(&amp;quot;DATABASE_URL&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might have found that it worked just fine locally and in your CI environment, but for some reason, not in
production. Very confusing! This is because the &lt;code&gt;System.get_env/1&lt;/code&gt; there is evaluated
at &lt;em&gt;compile time&lt;/em&gt; and not at runtime! If the correct environment variable isn&amp;#39;t set for your
production database url in whichever environment your release is compiled, then the configuration
for your application will be incorrect.&lt;/p&gt;
&lt;p&gt;What we really want is for this environment variable to be evaluated at runtime, instead of at compile-time, in whichever
environment it is running.&lt;/p&gt;
&lt;h3&gt;Compiled Releases Cannot Be Used in Different Environments&lt;/h3&gt;
&lt;p&gt;As noted above, the &lt;code&gt;System.get_env/1&lt;/code&gt; call is evaluated at compile time. This means that if
we have a staging environment that our application is deployed to for testing before
deployment to production, we&amp;#39;ll need to compile a separate OTP release for production. It is
far safer to be able to deploy the same build artifact that&amp;#39;s been tested on staging, directly to
production as this limits your ability to have differences between these two environments and
reduces the likelihood of bugs stemming from build or configuration issues.&lt;/p&gt;
&lt;h3&gt;Configuring Multiple Instances of an (OTP) Application&lt;/h3&gt;
&lt;p&gt;If your application depends on an OTP application that uses an application configuration for its
behavior, this essentially limits your ability to use it to only a single version. For example,
imagine we have an API client and we need to configure an API key for that client. That library
might get that API key by calling &lt;code&gt;Application.get_env(:api_client, :api_key)&lt;/code&gt;. Now, imagine that
you need to handle more than one API key? This would be basically impossible, since setting the
&amp;quot;correct&amp;quot; API key before calling some function in the library is too dangerous to rely on in a
highly parallel runtime like the BEAM!&lt;/p&gt;
&lt;h3&gt;Difficulties Using Non &lt;code&gt;config.exs&lt;/code&gt; Files for Configuration&lt;/h3&gt;
&lt;p&gt;There are different types of ways to configure an application—especially relating to
configuration and management of sensitive or secret values—and in the past, using something like
HashiCorp Vault, AWS Secrets Manager or some other configuration management tool was rather
difficult and unintuitive to use. There was a lot of work involved to make this stuff function at all, but
it relied on disparate, loosely-enforced conventions like the &lt;code&gt;REPLACE_OS_VARS&lt;/code&gt; setting in
&lt;code&gt;distillery&lt;/code&gt; or the &lt;code&gt;{:system, &amp;quot;ENV_VAR&amp;quot;}&lt;/code&gt; solution as a signal to libraries that &amp;quot;this
environment variable should be evaluated at runtime instead of compile time.&amp;quot;&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Recent and Upcoming Changes to Application Configuration&lt;/h2&gt;
&lt;p&gt;As I mentioned above, the problem of configuration is one that has been worked on quite frequently
over the last year or so. We&amp;#39;ve seen the inclusion of &lt;code&gt;mix release&lt;/code&gt; and the &lt;code&gt;Config&lt;/code&gt;,
&lt;code&gt;Config.Provider&lt;/code&gt; and &lt;code&gt;Config.Reader&lt;/code&gt; modules in Elixir 1.9, and in Elixir 1.10 we saw the
addition of the &lt;code&gt;Application.compile_env/3&lt;/code&gt; function that makes it crystal clear that any
configuration retrieved from there was set at compile-time and cannot be changed. These have all
been great changes!&lt;/p&gt;
&lt;p&gt;Coming, sometime in the future, will be the deprecation of using &lt;code&gt;Application.get_env/3&lt;/code&gt; at
compile-time altogether, which will make it even easier to avoid incorrectly using runtime
configuration by accident. But, I think most importantly, we&amp;#39;ve also seen the release of several
libraries that have made the distinction between runtime and compile-time configuration
clearer, including the tool we&amp;#39;ll look at today—&lt;code&gt;vapor&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can see that at the root of many of these problems is the need to cleanly and clearly separate
runtime from compile-time configuration. In addition to this, there is some work for libraries and
applications to do to change some of their APIs so that they rely less on application configuration and more
on arguments to functions when configuring an OTP application. A great example of the kind of
change that I&amp;#39;m talking about here is the
&lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.Repo.html#c:init/2&quot;&gt;&lt;code&gt;init/2&lt;/code&gt; callbacks&lt;/a&gt; that have been added to Ecto
and Phoenix.Endpoint. These make it trivially easy to configure these parts of your application
almost entirely at runtime!&lt;/p&gt;
&lt;h2&gt;Getting Started With &lt;code&gt;vapor&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;And so today, we&amp;#39;re going to look at how one might get started with &lt;code&gt;vapor&lt;/code&gt; and how we can
make changes over time to migrate to configuring an application in a safe, consistent,
and reliable way that will last well into the future. The first step, of course, is adding
&lt;code&gt;vapor&lt;/code&gt; as a dependency in &lt;code&gt;mix.exs&lt;/code&gt; by adding &lt;code&gt;{:vapor, &amp;quot;~&amp;gt; 0.8.0&amp;quot;}&lt;/code&gt; to your &lt;code&gt;deps()&lt;/code&gt; function.
&lt;code&gt;vapor&lt;/code&gt; has a lot of functionality, and what I&amp;#39;m going to show today is just &lt;em&gt;one&lt;/em&gt; way of using
it, but I find it to be a nice, easy migration, and so it&amp;#39;s what I like to recommend.&lt;/p&gt;
&lt;p&gt;So, now that we&amp;#39;ve added &lt;code&gt;vapor&lt;/code&gt; as a dependency, we need to start using it! We add &lt;code&gt;vapor&lt;/code&gt; to our
&lt;code&gt;start/2&lt;/code&gt; function in our application like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule VaporExample.Application do
  use Application

  def start(_type, _args) do
    Vapor.load!([%Vapor.Provider.Dotenv{}])

    children = [
       VaporExampleWeb.Endpoint,
       VaporExample.Repo
    ]

    opts = [strategy: :one_for_one, name: VaporExample.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;vapor&lt;/code&gt; has a great feature that allows it to read from a &lt;code&gt;.env&lt;/code&gt; or &lt;code&gt;.env.test&lt;/code&gt; file, and from
that, it populates the system environment for you at runtime. It does nothing if those files
don&amp;#39;t exist, so it&amp;#39;s totally safe to start with that for now. But, we don&amp;#39;t want to stop
there—we&amp;#39;re going to make one more small change before we&amp;#39;re done with our first step.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;config/config.exs&lt;/code&gt; let&amp;#39;s imagine that we had the following configuration for our
&lt;code&gt;VaporExample.Endpoint&lt;/code&gt; module (which is our Phoenix Endpoint) to set the port for our Endpoint to
&lt;code&gt;4000&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;config :vapor_example, VaporExample.Endpoint,
  http: [port: 4000]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is currently configured at compile-time, but there&amp;#39;s absolutely no reason it can&amp;#39;t be done
at runtime instead. So let&amp;#39;s do that! First, we&amp;#39;ll delete that &lt;code&gt;http: [port: 4000]&lt;/code&gt; line, then
we&amp;#39;ll add &lt;code&gt;PORT=4000&lt;/code&gt; to the &lt;code&gt;.env&lt;/code&gt; file I spoke about earlier to automatically set that
environment variable in our application, and then we&amp;#39;ll add a new function to
&lt;code&gt;VaporExample.Application&lt;/code&gt; called &lt;code&gt;load_system_env/0&lt;/code&gt;. This function&amp;#39;s job will be
taking environment variables and putting them in application configuration, and this is done once,
when we start the application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule VaporExample.Application do
  use Application

  def start(_type, _args) do
    Vapor.load!([%Vapor.Provider.Dotenv{}])
    load_system_env()

    children = [
       VaporExampleWeb.Endpoint,
       VaporExample.Repo
    ]

    opts = [strategy: :one_for_one, name: VaporExample.Supervisor]
    Supervisor.start_link(children, opts)
  end

  defp load_system_env() do
    port =
      case System.get_env(&amp;quot;PORT&amp;quot;) do
        nil -&amp;gt; raise(&amp;quot;Environment variable PORT must be set&amp;quot;)
        value -&amp;gt; String.to_integer(value)
      end

    Application.put_env(:vapor_example, VaporExample.Endpoint, http: [port: port])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, whether you&amp;#39;re starting your application with &lt;code&gt;mix&lt;/code&gt; or as a &lt;code&gt;release&lt;/code&gt;, in &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt; or
&lt;code&gt;prod&lt;/code&gt;, the behavior of configuring the port for your Endpoint to listen to will &lt;em&gt;always&lt;/em&gt; be the
same! The above implementation also ensures that our application doesn&amp;#39;t start if it&amp;#39;s not
configured correctly, which keeps us from running a partially (but maybe subtly) broken
application. This is a huge benefit, and really shows us that the rule for configuring an Elixir
application should really be &amp;quot;if it &lt;strong&gt;can&lt;/strong&gt; be set at runtime, it &lt;strong&gt;should&lt;/strong&gt; be set at runtime.&amp;quot;&lt;/p&gt;
&lt;p&gt;But wait, there&amp;#39;s more! We see that we&amp;#39;re kind of doing a lot just to turn one environment
variable into the application environment in our &lt;code&gt;load_system_env/0&lt;/code&gt; function. Luckily, &lt;code&gt;vapor&lt;/code&gt; can
make that easier for us! Besides being able to populate our system environment from a &lt;code&gt;.env&lt;/code&gt; file,
it can also declare bindings to that system environment to handle much of the work we did in
&lt;code&gt;load_system_env/0&lt;/code&gt; for us! So, we can change that function to look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule VaporExample.Application do
  use Application

  # ...

  defp load_system_env() do
    providers = %Vapor.Provider.Env{bindings: [
      {:port, &amp;quot;PORT&amp;quot;, map: &amp;amp;String.to_integer/1}
    ]}

    config = Vapor.Provider.load!(providers)

    Application.put_env(:vapor_example, VaporExample.Endpoint, http: [port: config.port])
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will do the same thing as our previous implementation—converting the string &lt;code&gt;&amp;quot;4000&amp;quot;&lt;/code&gt; to the
integer &lt;code&gt;4000&lt;/code&gt; and returning an error if the variable isn&amp;#39;t set, so that we can raise an exception—but
does so with a nice, consistent API.&lt;/p&gt;
&lt;p&gt;Now, with these basics in place, you can start moving over compile-time configuration to runtime
easily! After everything that can be set at runtime is set at runtime, you could then move on to
trying to reduce the use of the application environment altogether and use things like the
&lt;code&gt;init/2&lt;/code&gt; callback in your &lt;code&gt;Endpoint&lt;/code&gt; and &lt;code&gt;Repo&lt;/code&gt;, and find other places where a dependency
on the application environment can be replaced by passing arguments to functions instead.&lt;/p&gt;
&lt;p&gt;Moving over to this style of configuration will ensure that your Elixir applications are
configured correctly well into the future, and should hopefully also make for a more consistent
and clear configuration experience for your whole team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Use gRPC in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/03/24/how-to-use-grpc-in-elixir.html"/>
    <id>https://blog.appsignal.com/2020/03/24/how-to-use-grpc-in-elixir.html</id>
    <published>2020-03-24T00:00:00+00:00</published>
    <updated>2020-03-24T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Learn about gRPC and how to use it in an Elixir application.</summary>
    <content type="html">&lt;p&gt;In today&amp;#39;s post, we&amp;#39;ll learn what gRPC is, when you should reach for such a tool, and some of
the pros and cons of using it. After going over an introduction of gRPC, we&amp;#39;ll dive
right into a sample application where we&amp;#39;ll build an Elixir backend API powered by gRPC.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s jump right in!&lt;/p&gt;
&lt;h2&gt;What Is gRPC and How Does It Work?&lt;/h2&gt;
&lt;p&gt;gRPC is a framework used to enable a remote procedure call (RPC) style of communication. RPC is a style of system
communication where a client can directly invoke exposed methods on a server. From the client&amp;#39;s perspective, it feels no
different than making a call to a local function or method as long as you provide the applicable parameters and handle
the return type appropriately. gRPC facilitates this communication by providing 2 things for you:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A client library which can be used to invoke allowed procedures&lt;/li&gt;
&lt;li&gt;A consistent data serialization standard via Protocol Buffers&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#39;s break these two items down so we can appreciate the inner workings of gRPC. When creating a gRPC server, you&amp;#39;ll
have to define what procedures are invokable from the client, what inputs they accept, and what outputs they return.
This interface specification is what allows client libraries (generally called gRPC stubs) to be automatically generated
for various languages and runtimes as the contract for the remote procedure call is explicitly defined. This gRPC client
library can then communicate with the server using Protocol Buffers. Protocol Buffers provide a mechanism for
serializing and deserializing the payloads (both request and response) so that you can operate on the data with types
native to your language. The diagram available in the gRPC documentation can help visualize &lt;a href=&quot;https://grpc.io/docs/guides/&quot;&gt;this interaction&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-03/landing-2.svg&quot; alt=&quot;gRPC Diagram&quot;/&gt;
&lt;em&gt;Source: &lt;a href=&quot;https://grpc.io&quot;&gt;https://grpc.io&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One thing that we haven&amp;#39;t discussed yet is how data is transmitted between the client and the server. For this, gRPC
leans on the HTTP/2 protocol. By using HTTP/2 as the underlying protocol, gRPC is able to support features such as
bi-directional data streaming and several other features that are not available in HTTP/1.1.&lt;/p&gt;
&lt;h2&gt;When Would You Use gRPC Over REST/GraphQL?&lt;/h2&gt;
&lt;p&gt;The obvious question that may come to mind is: &amp;quot;How does gRPC compare to REST/GraphQL, and when do I use one over the
other?&amp;quot;.&lt;/p&gt;
&lt;p&gt;In general, if you plan to use gRPC for a frontend application, there are a couple of caveats that you need to
keep in mind. In order to serialize and deserialize Protocol Buffer payloads from your Javascript application, you&amp;#39;ll
have to leverage &lt;a href=&quot;https://github.com/grpc/grpc-web&quot;&gt;grpc-web&lt;/a&gt;. In addition, you&amp;#39;ll also need to run a proxy on the backend (the
default supported gRPC proxy is Envoy) since browsers cannot talk directly to gRPC servers. Depending on your resources
and time constraints, this may be a show stopper; in which case, REST and GraphQL will do just fine.&lt;/p&gt;
&lt;p&gt;If frontend application communication is not a requirement, and instead what you require is inter-microservice
communication from within your service cluster, then the barrier to entry for gRPC gets lowered considerably. At the
time of writing, gRPC currently has client libraries and tooling for most mainstream languages including Elixir, Python,
C++, Go, Ruby, to name a few. I would argue that the barrier to entry for consuming a RESTful API is still much lower
than consuming a gRPC service given that all you need for the former is an HTTP client, which is baked into most
languages and runtimes these days.&lt;/p&gt;
&lt;p&gt;On the other hand, if you are willing to make the investment, you do get the added benefits of having your responses and
requests checked against the Protocol Buffer specification that is used for code generation. This, in turn, provides you
with some guarantees as to what you can expect on the client-side and the server-side. This guarantee and
introspection is also something that you get with GraphQL when you define your server schemas. An added benefit of
GraphQL over gRPC is that you are able to dynamically request embedded properties from within your schema depending on
the query that you make to your backend server.&lt;/p&gt;
&lt;p&gt;Like most things in the software engineering field, the technology you choose will largely depend on your application.
Below are my personal TL;DR rules of thumb regarding the various technologies:&lt;/p&gt;
&lt;p&gt;gRPC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use: When communicating between microservices in my service cluster or if performance is a requirement&lt;/li&gt;
&lt;li&gt;Don&amp;#39;t use: When I need to transmit data from the browser to the backend&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;GraphQL:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use: When I need to aggregate data from multiple microservices for the purposes of streamlining frontend development,
or if my frontend data requirements are dynamic&lt;/li&gt;
&lt;li&gt;Don&amp;#39;t use: When communicating between microservices in my service cluster, or if my API needs to be used by the lowest
common denominator of consumers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;REST:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use: When I need to put something together quickly or if I need to cater to the lowest common denominator of consumers&lt;/li&gt;
&lt;li&gt;Don&amp;#39;t use: If I require any kind of type checking or if I want to reduce payload sizes over the wire&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Experimenting With gRPC in Elixir&lt;/h2&gt;
&lt;p&gt;With all the theory out of the way, it&amp;#39;s time to get our hands dirty and experiment with wiring up a gRPC server. In
order to keep us focused on the gRPC experience, we&amp;#39;ll opt for having a backend powered by an Agent versus an actual
database, but all of the concepts should be easily transferable to an application backed by Postgres, for example. Our
gRPC application will be a simple user management service where we can create and fetch users. After creating our
Elixir service, we&amp;#39;ll interact with it via grpcurl, which is effectively cURL, but for gRPC. If at any point you get
stuck or require the source code, feel free to &lt;a href=&quot;https://github.com/akoutmos/sample_app&quot;&gt;check it out on GitHub&lt;/a&gt;. With all that being said, let&amp;#39;s dive right in!&lt;/p&gt;
&lt;p&gt;Before creating our Elixir project, there are a couple of things that we require on our machine in order to properly
develop and test our application. We&amp;#39;ll first need to install &lt;code&gt;protoc&lt;/code&gt; so that &lt;code&gt;.proto&lt;/code&gt; files can be compiled
appropriately. If you are on an OSX machine, you can run &lt;code&gt;brew install protobuf&lt;/code&gt;, otherwise, &lt;a href=&quot;https://github.com/protocolbuffers/protobuf/blob/master/src/README.md&quot;&gt;see instructions&lt;/a&gt; specific to
your platform. Now, with &lt;code&gt;protoc&lt;/code&gt; available on your machine, you&amp;#39;ll also want to install &lt;code&gt;grpcurl&lt;/code&gt; so that you can
interact with the application. Once again, if you are on an OSX machine, you can run &lt;code&gt;brew install grpcurl&lt;/code&gt;, otherwise, &lt;a href=&quot;https://github.com/fullstorydev/grpcurl#installation&quot;&gt;check for instructions specific to your platform&lt;/a&gt;.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Lastly, you&amp;#39;ll want to run &lt;code&gt;mix escript.install hex protobuf&lt;/code&gt; and ensure that &lt;code&gt;protoc-gen-elixir&lt;/code&gt; script is available on
your path (if you use ASDF as your runtime version manager, this requires running &lt;code&gt;asdf reshim elixir&lt;/code&gt;). With all that
boilerplate done, you can run &lt;code&gt;mix new sample_app --sup&lt;/code&gt; to get a new application started.&lt;/p&gt;
&lt;p&gt;Once inside your sample application directory, you&amp;#39;ll want to update your &lt;code&gt;mix.exs&lt;/code&gt; file to include our gRPC related
dependencies. For this application, we will be leveraging &lt;a href=&quot;https://github.com/elixir-grpc/grpc&quot;&gt;https://github.com/elixir-grpc/grpc&lt;/a&gt; and
&lt;a href=&quot;https://github.com/tony612/protobuf-elixir&quot;&gt;https://github.com/tony612/protobuf-elixir&lt;/a&gt;. In order to bring these two dependencies into your project, ensure that
your &lt;code&gt;deps/0&lt;/code&gt; function looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:grpc, &amp;quot;~&amp;gt; 0.5.0-beta&amp;quot;},
    {:cowlib, &amp;quot;~&amp;gt; 2.8.0&amp;quot;, hex: :grpc_cowlib, override: true}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, run &lt;code&gt;mix deps.get&lt;/code&gt; from the terminal to pull down all necessary project
dependencies. Next, you&amp;#39;ll want to create a configuration file at &lt;code&gt;config/config.exs&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;use Mix.Config

# Configures Elixir&amp;#39;s Logger
config :logger, :console, format: &amp;quot;$time $metadata[$level] $message\n&amp;quot;

config :grpc, start_server: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we&amp;#39;ll want to create the required Protocol Buffer definitions for our application. The &lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/proto3&quot;&gt;Protocol Buffer specification&lt;/a&gt; is fairly large and we&amp;#39;ll only be using a small subset of it to keep things simple. Create a file
&lt;code&gt;sample_app.proto&lt;/code&gt; at the root of your project with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;syntax = &amp;quot;proto3&amp;quot;;

package sample_app;

service User {
  rpc Create (CreateRequest) returns (UserReply) {}
  rpc Get (GetRequest) returns (UserReply) {}
}

message UserReply {
  int32 id = 1;
  string first_name = 2;
  string last_name = 3;
  int32 age = 4;
}

message CreateRequest {
  string first_name = 1;
  string last_name = 2;
  int32 age = 3;
}

message GetRequest {
  int32 id = 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, our Protocol Buffer definition is fairly straightforward and easy to read. We define a service that
exposes two RPC methods—&lt;code&gt;Create&lt;/code&gt; and &lt;code&gt;Get&lt;/code&gt;. We also define the types that each of those RPC calls takes as
input and returns as a result. With the &lt;code&gt;sample_app.proto&lt;/code&gt; file in place, we&amp;#39;ll want to open up a terminal and run the
following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ protoc --elixir_out=plugins=grpc:./lib sample_app.proto
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#39;ll notice that this command produces a file &lt;code&gt;lib/sample_app.pb.ex&lt;/code&gt; with several modules within it. If you look
carefully, you&amp;#39;ll see that the code that was generated is the Elixir representation of the &lt;code&gt;sample_app.proto&lt;/code&gt; file that
we wrote. It contains all of the types that we defined along with the RPC method definitions. With our auto-generated
code in place, let&amp;#39;s get to work on the actual RPC handlers.&lt;/p&gt;
&lt;p&gt;As previously mentioned, we&amp;#39;ll be using an Agent to persist state across gRPC calls instead of a database, for the sake
of simplicity. Our agent will have the ability to look up users via their ID, and will also be able to create new users.
Create a file &lt;code&gt;lib/user_db.ex&lt;/code&gt; with the following code which provides that functionality:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule UserDB do
  use Agent

  def start_link(_) do
    Agent.start_link(
      fn -&amp;gt;
        {%{}, 1}
      end,
      name: __MODULE__
    )
  end

  def add_user(user) do
    Agent.get_and_update(__MODULE__, fn {users_map, next_id} -&amp;gt;
      updated_users_map = Map.put(users_map, next_id, user)

      {Map.put(user, :id, next_id), {updated_users_map, next_id + 1}}
    end)
  end

  def get_user(id) do
    Agent.get(__MODULE__, fn {users_map, _next_id} -&amp;gt;
      Map.get(users_map, id)
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, we can create our RPC handlers for creating and getting users. Create a file &lt;code&gt;lib/sample_app.ex&lt;/code&gt;
with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule SampleApp.Endpoint do
  use GRPC.Endpoint

  intercept GRPC.Logger.Server
  run SampleApp.User.Server
end

defmodule SampleApp.User.Server do
  use GRPC.Server, service: SampleApp.User.Service

  def create(request, _stream) do
    new_user =
      UserDB.add_user(%{
        first_name: request.first_name,
        last_name: request.last_name,
        age: request.age
      })

    SampleApp.UserReply.new(new_user)
  end

  def get(request, _stream) do
    user = UserDB.get_user(request.id)

    if user == nil do
      raise GRPC.RPCError, status: :not_found
    else
      SampleApp.UserReply.new(user)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our file defines two modules. The &lt;code&gt;SampleApp.Endpoint&lt;/code&gt; module defines the gRPC server and provides the
handler module to service requests. The &lt;code&gt;SampleApp.User.Server&lt;/code&gt; module contains the actual implementations of the two
RPC calls that we defined. You&amp;#39;ll notice that for each of the handlers, we provide the correct return type (as defined in
our Protocol Buffer file). When we encounter an error (in this case, looking up a user that doesn&amp;#39;t exist), we raise a
&lt;code&gt;GRPC.RPCError&lt;/code&gt; with the appropriate status code.&lt;/p&gt;
&lt;p&gt;All that is left now is to start up our Agent and our gRPC server, and we&amp;#39;re good to go. Open up
&lt;code&gt;lib/sample_app/application.ex&lt;/code&gt; and ensure that your process &lt;code&gt;children&lt;/code&gt; list looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;children = [
  UserDB,
  {GRPC.Server.Supervisor, {SampleApp.Endpoint, 50051}}
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, you should be able to run &lt;code&gt;mix grpc.server&lt;/code&gt; from the terminal to start your gRPC server. In another
terminal session (and from within the project directory), you should be able to use &lt;code&gt;grpcurl&lt;/code&gt; commands to interact with
your application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ grpcurl -plaintext -proto sample_app.proto -d &amp;#39;{&amp;quot;first_name&amp;quot;: &amp;quot;Bob&amp;quot;, &amp;quot;last_name&amp;quot;: &amp;quot;Smith&amp;quot;, &amp;quot;age&amp;quot;: 40}&amp;#39; localhost:50051 sample_app.User.Create
{
  &amp;quot;id&amp;quot;: 1,
  &amp;quot;firstName&amp;quot;: &amp;quot;Bob&amp;quot;,
  &amp;quot;lastName&amp;quot;: &amp;quot;Smith&amp;quot;,
  &amp;quot;age&amp;quot;: 40
}

$ grpcurl -plaintext -proto sample_app.proto -d &amp;#39;{&amp;quot;id&amp;quot;: 1}&amp;#39; localhost:50051 sample_app.User.Get
{
  &amp;quot;firstName&amp;quot;: &amp;quot;Bob&amp;quot;,
  &amp;quot;lastName&amp;quot;: &amp;quot;Smith&amp;quot;,
  &amp;quot;age&amp;quot;: 40
}

$ grpcurl -plaintext -proto sample_app.proto -d &amp;#39;{&amp;quot;id&amp;quot;: 2}&amp;#39; localhost:50051 sample_app.User.Get
ERROR:
  Code: NotFound
  Message: Some requested entity (e.g., file or directory) was not found
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks for sticking with me to the end. Hopefully, you learned a thing or two about gRPC and how to go about
using it within an Elixir application. If you would like to learn more about gRPC or any of the tools that I mentioned,
I suggest going through the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/elixir-grpc/grpc&quot;&gt;elixir-grpc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tony612/protobuf-elixir&quot;&gt;protobuf-elixir&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/akoutmos/sample_app&quot;&gt;Our sample app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building Compile-time Tools With Elixir&#039;s Compiler Tracing Features</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/03/10/building-compile-time-tools-with-elixir-compiler-tracing-features.html"/>
    <id>https://blog.appsignal.com/2020/03/10/building-compile-time-tools-with-elixir-compiler-tracing-features.html</id>
    <published>2020-03-10T00:00:00+00:00</published>
    <updated>2020-03-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Check out one of Elixir&#039;s latest features—compiler tracing—and find out why you should consider using it.</summary>
    <content type="html">&lt;p&gt;Elixir 1.10 was recently released, and with that release came a little-known, but very
interesting feature—compiler tracing. This feature means that as the Elixir compiler is
compiling your code, it can emit messages whenever certain kinds of things are compiled. This
ability to know what&amp;#39;s going on when Elixir is compiling our code might seem simple, but
it actually opens up a lot of doors for opportunities to build customized compile-time
tooling for Elixir applications.&lt;/p&gt;
&lt;p&gt;In this post, we&amp;#39;ll go over several kinds of tooling you might consider building with this new
feature, explain why these tools are a great idea, and then show a quick implementation of a basic check
one might write to automatically enforce a project-specific rule in an application.&lt;/p&gt;
&lt;h2&gt;Why You Should Build Your Own Tools&lt;/h2&gt;
&lt;p&gt;There is already a great deal of excellent tooling in the Elixir community that can help us build
better, safer, more consistent applications. But this tooling is very generalized to a lowest
common denominator that might apply to any Elixir application, and there are often rules or
conventions that a team might want to enforce that are specific to that team or the domain in
which they&amp;#39;re working. Normally, this is done manually with practices like pull request reviews,
pair programming, or manually enforced style guides.&lt;/p&gt;
&lt;p&gt;However, there are a great many of these rules that can be easily enforced automatically! Moving this
responsibility away from humans and onto computers has many benefits. First and foremost, it frees
up time for humans to do what they do best—think about complicated problems. When we&amp;#39;re not
worrying about formatting and naming rules, we can spend more time thinking about higher-level
problems such as design and complex domain problems.&lt;/p&gt;
&lt;p&gt;It&amp;#39;s also great to get faster feedback when we&amp;#39;re working on something. Instead of waiting for someone to
review your PR, only to tell you that there&amp;#39;s some variable that is named incorrectly according to
your team&amp;#39;s naming conventions, you can get that feedback quickly with the tools you&amp;#39;ve
built. If you&amp;#39;ve integrated the tools with whatever editor you&amp;#39;re using, the feedback can
happen almost instantly.&lt;/p&gt;
&lt;p&gt;Lastly, these sorts of tools can help offload a rather difficult interpersonal task from your
team members. Having to remind your colleagues to fix things like formatting and styling in a PR
review can strain your relationships. Instead, when these reminders come from an automated
check, it leads to less frustration with your colleagues and better team morale. This is a
frequently under-valued benefit of this kind of automation.&lt;/p&gt;
&lt;p&gt;Today, I&amp;#39;m going to show you how to use Elixir 1.10&amp;#39;s compiler tracing features to build a
simple check that will enforce a rule that all modules that define an Ecto schema must use the
application&amp;#39;s extension of &lt;code&gt;Ecto.Schema&lt;/code&gt; and not &lt;code&gt;Ecto.Schema&lt;/code&gt; directly. This is a fairly common
pattern in applications that use Ecto. Let&amp;#39;s imagine that we&amp;#39;ve defined a module called
&lt;code&gt;MyApp.Schema&lt;/code&gt; that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# my_app/schema.ex
defmodule MyApp.Schema do
  defmacro __using__(_) do
    quote do
      use Ecto.Schema
      import MyApp.Helpers
      @derive Jason.Encoder
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Normally, enforcing that all schemas use this macro would need to be done manually, but with this
tracer enabled, if someone accidentally forgets to use &lt;code&gt;MyApp.Schema&lt;/code&gt; and uses &lt;code&gt;Ecto.Schema&lt;/code&gt;
instead, they&amp;#39;ll get a compilation warning.&lt;/p&gt;
&lt;h2&gt;Implementing a Basic Tracer&lt;/h2&gt;
&lt;p&gt;A valid tracer for Elixir 1.10&amp;#39;s compiler events is any module that implements the &lt;code&gt;trace/2&lt;/code&gt;
function. This function should return &lt;code&gt;:ok&lt;/code&gt;. The arguments it accepts can vary depending on
which event is being emitted. Each event that the compiler emits can have a slightly
different signature (which we&amp;#39;ll go over later), but for now, we&amp;#39;re going to just focus on the one
thing we care about for this example—the &lt;code&gt;:remote_macro&lt;/code&gt; event.&lt;/p&gt;
&lt;p&gt;To get this working quickly, we&amp;#39;re going to write a quick &lt;code&gt;.exs&lt;/code&gt; script to do
this task for us (because of many reasons that we won&amp;#39;t go into today). Here&amp;#39;s what that task
looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# scripts/schema_validator.exs
defmodule SchemaValidator do
  def run() do
    :ets.new(:schemas, [:named_table, :public])
    Mix.Task.clear()
    Mix.Task.run(&amp;quot;compile&amp;quot;, [&amp;quot;--force&amp;quot;, &amp;quot;--tracer&amp;quot;, __MODULE__])
  end

  @spec trace(tuple, Macro.Env.t()) :: :ok
  def trace({:remote_macro, _meta, MyApp.Schema, :__using__, 1}, env) do
    :ets.insert(:schemas, {env.module, true})
    :ok
  end

  def trace({:remote_macro, meta, Ecto.Schema, :__using__, 1}, env) do
    case :ets.lookup(:schemas, env.module) do
      [] -&amp;gt; IO.warn(&amp;quot;#{env.file}:#{meta[:line]} - #{inspect(env.module)} should use `MyApp.Schema`&amp;quot;, [])
      _ -&amp;gt; :ok
    end
  end

  def trace(_, _), do: :ok
end

SchemaValidator.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#39;s it! With that, we can run &lt;code&gt;mix run scripts/schema_validator.exs&lt;/code&gt; and have a very basic
version of this check working! So, let&amp;#39;s dive in and explain what&amp;#39;s going on there, starting
with &lt;code&gt;run/0&lt;/code&gt;. In that function, we start an ETS table that will hold the global state for our task.
It&amp;#39;s important to remember that the Elixir compiler runs in parallel, with each module compiled in
its own process, so we&amp;#39;ll need a place to keep the data we&amp;#39;re collecting during compilation, and
ETS is as good a place as any—we just need to remember to make it a &lt;code&gt;:public&lt;/code&gt; table.&lt;/p&gt;
&lt;p&gt;Then we have to run &lt;code&gt;Mix.Task.clear()&lt;/code&gt; to clear out mix&amp;#39;s cache of tasks that have already been
run, including &lt;code&gt;compile&lt;/code&gt;. Otherwise, mix is nice enough to not duplicate tasks that have already
been run to speed things up and &lt;code&gt;compile&lt;/code&gt; would return &lt;code&gt;:noop&lt;/code&gt; and not actually compile our code.&lt;/p&gt;
&lt;p&gt;Once we&amp;#39;ve cleared that cache, we run &lt;code&gt;Mix.Task.run(&amp;quot;compile&amp;quot;, [&amp;quot;--force&amp;quot;, &amp;quot;--tracer&amp;quot;, __MODULE__])&lt;/code&gt;.
This compiles our code, forcing a full compilation of all modules in our application, using
the current module as the tracer for the compilation process. This is where we&amp;#39;re hooking into the
trace events emitted by the compiler.&lt;/p&gt;
&lt;p&gt;Now, as Elixir is compiling our code, it&amp;#39;s going to be calling &lt;code&gt;trace/2&lt;/code&gt; with the events that take
place during compilation. We&amp;#39;re looking specifically for two of these events—when we call
&lt;code&gt;use MyApp.Schema&lt;/code&gt; and when &lt;code&gt;use Ecto.Schema&lt;/code&gt; is called. Because of how macro expansion works,
both of those modules will end up having their &lt;code&gt;__using__/1&lt;/code&gt; macros called, but if folks are using
&lt;code&gt;MyApp.Schema&lt;/code&gt; in their schema definition, then the message showing that &lt;code&gt;MyApp.Schema.__using__/1&lt;/code&gt; has
been called will be emitted before the message showing that &lt;code&gt;Ecto.Schema.__using__/1&lt;/code&gt; has been called, and
this is what we use for our check.&lt;/p&gt;
&lt;p&gt;When we get the message that &lt;code&gt;MyApp.Schema.__using__/1&lt;/code&gt; has been called, we put the module that
called it—which we get from &lt;code&gt;env.module&lt;/code&gt;—in our ETS table. Then, if we get a message that
&lt;code&gt;Ecto.Schema.__using__/1&lt;/code&gt; has been called, we check to see if &lt;code&gt;MyApp.Schema.__using__/1&lt;/code&gt; has been
called for the same module. If it has, then we&amp;#39;re sure that the module, in that case, is doing the
right thing. If it hasn&amp;#39;t, then we&amp;#39;re sure that the module is using &lt;code&gt;Ecto.Schema&lt;/code&gt; directly, and we
can emit our warning message letting the developer know what they should be doing instead.&lt;/p&gt;
&lt;p&gt;One important note is that we &lt;strong&gt;absolutely need&lt;/strong&gt; to have that second catch-all function
there, since every time a possible event is emitted, our function will be called, and if one of our
tracer functions fails, then compilation will fail at that point. So if any message doesn&amp;#39;t match
the event that we care about, which is the pattern we&amp;#39;re looking for, we&amp;#39;re just going to
ignore it.&lt;/p&gt;
&lt;h2&gt;Events We Can Consume&lt;/h2&gt;
&lt;p&gt;There is great documentation about the types of events that the Elixir compiler will emit trace
messages for in the documentation of the &lt;a href=&quot;https://hexdocs.pm/elixir/Code.html#module-compilation-tracers&quot;&gt;&lt;code&gt;Code&lt;/code&gt;module&lt;/a&gt;. The ones I&amp;#39;ve been most
interested in when it comes to potential uses of tooling are &lt;code&gt;{:import, meta, module, opts}&lt;/code&gt;, so
I can see if we&amp;#39;re ever importing a certain module (which can really slow down compilation times),
&lt;code&gt;{:compile_env, app, path, return}&lt;/code&gt; to see all the places that we&amp;#39;re accessing compile-time
application configuration in the application, and &lt;code&gt;{:local_function, meta, module, name, arity}&lt;/code&gt;
combined with &lt;code&gt;{:remote_function, meta, module, name, arity}&lt;/code&gt;, so that I can find functions that could
be safely made private (or even deleted!).&lt;/p&gt;
&lt;p&gt;These are just some of the ideas out there, and there are already really great tools taking
advantage of this new feature starting to be released. A great example of this that I like to point to
is Sasa Juric&amp;#39;s &lt;a href=&quot;https://github.com/sasa1977/boundary&quot;&gt;&lt;code&gt;boundary&lt;/code&gt;&lt;/a&gt; package, but I&amp;#39;m sure more are
in the works.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Now that we&amp;#39;ve seen some of the kinds of tooling one can build with compiler tracing, why these
tools are a great addition to a project, and walked through the implementation of a basic check,
now it&amp;#39;s time to think about what things you&amp;#39;d like to automate to make your life easier! What
rules or conventions might be easier to enforce in your application with compiler tracing instead
of with manual review?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Migrating Production Data in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/02/25/migrating-production-data-in-elixir.html"/>
    <id>https://blog.appsignal.com/2020/02/25/migrating-production-data-in-elixir.html</id>
    <published>2020-02-25T00:00:00+00:00</published>
    <updated>2020-02-25T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Find out how to handle migrations that involve systems other than the database itself, while keeping the entire process idempotent and backward-compatible.</summary>
    <content type="html">&lt;p&gt;When requirements change for your product, there arises a need to change not only the codebase but also the existing data that already lives in production.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;re performing the changes locally, the whole process seems fairly simple. You test your new feature against a sparkling clean database, the test suite is green, and the feature looks great. Then you deploy, and everything goes to hell because you forgot that production was in a slightly different state.&lt;/p&gt;
&lt;p&gt;In this post, you&amp;#39;ll learn how to handle migrations that may involve systems other than the database itself, while keeping the entire process idempotent and backward-compatible.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;The post mostly requires knowledge of how database migrations work in frameworks such as Ruby on Rails and Phoenix. It also helps to have some knowledge of the constraints of deploying updates to an application that already has existing data in use.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;ve ever dealt with a production system, this is probably nothing new to you.
Other tools, such as &lt;a href=&quot;https://redis.io&quot;&gt;Redis&lt;/a&gt;, are mentioned, but you don&amp;#39;t need to know anything about them, other than the fact that they exist.&lt;/p&gt;
&lt;h2&gt;Migrating Feature Flags to Redis&lt;/h2&gt;
&lt;p&gt;Here&amp;#39;s an example of a list of feature flags, or settings, for your application:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;Feature            | Enabled
2fa_sms            | true
notifications_beta | false
pagination         | true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You now need to migrate these over to Redis, to take advantage of its Pub-Sub and notify all of your services when a flag gets toggled.&lt;/p&gt;
&lt;p&gt;You need to somehow get these flags over to the other system, without breaking the behavior in production.&lt;/p&gt;
&lt;p&gt;One simple way to do this without having to patch your code to temporarily manage two storage systems simultaneously is to automatically perform this migration right after the deploy.
This is typically where database migrations happen. But this is no common database migration. It’s not even a good idea to do it all at once since it touches a Redis instance, which has nothing to do with your database.
To solve this, you can write a mechanism similar to those migrations, but tailored to your own needs. Imagine the following script:&lt;/p&gt;
&lt;p&gt;You need to update your order management to also include the converted price in EUR (because the finance department needs it).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule DataMigrator.Migrations.MigrateFlagsToRedis do
  import Ecto.{Query, Changeset}
  alias App.{Flag, Repo, Redis}

  def run do
    Redis.start_link()

    |&amp;gt; Repo.all(Flag)
    |&amp;gt; Enum.each(&amp;amp;migrate_flag/1)

    :ok
  end

  defp migrate_flag(%Flag{name: name, enabled: enabled}) do
    Redis.put(name, enabled)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;But how do we guarantee that this runs automatically? And even more important, how do we make this idempotent? We certainly don’t want this running again by accident a few days later when the database flags have long become outdated.&lt;/p&gt;
&lt;h2&gt;Data Migrations&lt;/h2&gt;
&lt;p&gt;This is where the concept of migrations comes in handy. Ecto migrations keep a table in PostgreSQL tracking which migrations have already been executed. On every run, the system checks which ones are new and runs only those. We can do something similar ourselves.&lt;/p&gt;
&lt;p&gt;First, let’s write a function that looks for new migrations at &lt;code&gt;./priv/data_migrations&lt;/code&gt; for any new files:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule App.DataMigrator do
  alias App.Repo
  alias DataMigrator.DataMigration

  def new_migrations do
    already_migrated = Repo.all(from dm in DataMigration, select: dm.version)

    Application.app_dir(:app, &amp;quot;priv/data_migrations/&amp;quot;)
    |&amp;gt; Path.join(&amp;quot;*&amp;quot;)
    |&amp;gt; Path.wildcard()
    |&amp;gt; Enum.map(&amp;amp;extract_migration_info/1)
    |&amp;gt; Enum.reject(fn
      # reject migrations that have already ran
      {version, _, _} -&amp;gt; Enum.member?(migrated_versions, version)
      _ -&amp;gt; true
    end)
    |&amp;gt; Enum.map(fn {version, _name, file} -&amp;gt;
      # load elixir module in given file
      [{mod, _}] = Code.load_file(file)
      {mod, version}
    end)
  end

  defp extract_migration_info(file) do
    file
    |&amp;gt; Path.basename()
    |&amp;gt; Path.rootname()
    |&amp;gt; Integer.parse()
    |&amp;gt; case do
      {integer, _} -&amp;gt;
        {integer, file}

      _ -&amp;gt;
        nil
    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this snippet, we can write data migrations into &lt;code&gt;./priv/data_migration&lt;/code&gt; using a name similar to what is done for database migrations, such as &lt;code&gt;202002111319_migrate_flags_to_redis.exs&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;new_migrations/0&lt;/code&gt; function will find those files, filter out the ones that are present in a &lt;code&gt;DataMigration&lt;/code&gt; model (meaning migrations that have already run, and return that as &lt;code&gt;[{202002111319,&lt;/code&gt; &lt;code&gt;DataMigrator.Migrations.``MigrateFlagsToRedis}]&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;The Migrator&lt;/h2&gt;
&lt;p&gt;Next, it’s purely a matter of writing a task that runs all new migrations and stores their timestamp in the &lt;code&gt;DataMigration&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule DataMigrator do
  ...

  def run() do
    Application.load(:app)
    Repo.start_link()

    new_migrations()
    |&amp;gt; Enum.map(&amp;amp;execute_data_migration/1)
  end

  def execute_data_migration({version, mod}) do
    case mod.run() do
      :ok -&amp;gt;
        # migration successful, track it
        Repo.insert!(%DataMigration{
          version: version,
          created_at: DateTime.truncate(DateTime.utc_now(), :second)
        })

        :ok

      {:error, error} -&amp;gt;
        # migration failed, most likely a bug that needs fixing
        Logger.error(&amp;quot;Data migration failed with error #{inspect(error)}&amp;quot;)
        System.halt(1)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, using Mix releases, we can easily set this up as a pre-start hook for the next time our application is deployed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;#rel/start/10_data_migrations.sh

$RELEASE_ROOT_DIR/bin/app command Elixir.App.DataMigrator run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By doing this, we’re able to immediately change our code to use Redis instead of PostgreSQL flags, as well as having a guarantee that once our refactor is deployed, all flags will automatically be migrated, without us needing to ensure backward compatibility.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With these suggestions, you should be able to simplify some otherwise painful migrations within your system, particularly those that involve keeping both an old and a new system living in parallel. Instead, you can just automate the migration to the new one, and have this as a hook that gets triggered automatically once you deploy.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Monitoring the Erlang VM With AppSignal&#039;s Magic Dashboard</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/02/04/elixir-monitoring-erlangvm-with-magic-dashboards.html"/>
    <id>https://blog.appsignal.com/2020/02/04/elixir-monitoring-erlangvm-with-magic-dashboards.html</id>
    <published>2020-02-04T00:00:00+00:00</published>
    <updated>2020-02-04T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this post, we walk through monitoring the Erlang VM with the metrics automatically shown in AppSignal&#039;s Magic Dashboard.</summary>
    <content type="html">&lt;p&gt;Today, we will dive into one of the hard parts of using any monitoring - making sense out of all the data that is emitted. We think this is one of the hard parts. And being developers building for developers, we think a lot like you do -- we think. Pun intended.&lt;/p&gt;
&lt;p&gt;Nowadays, we monitor AppSignal with AppSignal (on a separate setup), so we are still dogfooding all the time. We still run into challenges as you do, often before you.&lt;/p&gt;
&lt;h2&gt;Magic Dashboards&lt;/h2&gt;
&lt;p&gt;We believe one of the harder challenges is finding the right data and making sense of it. Once we discover what works best for a certain setup, we don&amp;#39;t just keep the solution to ourselves, we make it into a solution that&amp;#39;s available to all of our users.&lt;/p&gt;
&lt;p&gt;We call this solution Magic Dashboards. Based on the architecture that you are running, we add dashboards that make sense for that architecture.&lt;/p&gt;
&lt;p&gt;If you are running a recent version of the AppSignal integration, magic dashboards will show up when you add a new application.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-01/erlang_splash.png&quot; alt=&quot;Erlang VM Magic Dashboard image&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Erlang VM Magic Dashboard&lt;/h2&gt;
&lt;p&gt;A Magic Dashboard that we made for the Elixir integration is the Erlang VM dashboard. It has graphs metrics on IO, schedulers, processes and memory. This is what it looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2020-01/erlang_bdashboard.png&quot; alt=&quot;Erlang VM Magic Dashboard image&quot;/&gt;&lt;/p&gt;
&lt;h3&gt;IO&lt;/h3&gt;
&lt;p&gt;This shows the amount of input and output you have cumulatively, expressed in kb.&lt;/p&gt;
&lt;h3&gt;Schedulers&lt;/h3&gt;
&lt;p&gt;This graph shows the total number of available schedulers and the number of online schedulers. Erlang&amp;#39;s schedulers schedule CPU time between your processes. The number of schedulers defaults to the number of CPU cores on the machine.&lt;/p&gt;
&lt;p&gt;If you want to know more about schedulers, here’s &lt;a href=&quot;https://hamidreza-s.github.io/erlang/scheduling/real-time/preemptive/migration/2016/02/09/erlang-scheduler-details.html&quot;&gt;a good article on Hamidreza Soleimani’s Blog on why the details of schedulers are important&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Processes&lt;/h3&gt;
&lt;p&gt;The number of processes and the limit are plotted here. The limit is the maximum number of simultaneously existing processes at the local node. If you reach the limit, the process will raise an exception. But the default Erlang limit is 262144, which should be high enough for almost all applications.&lt;/p&gt;
&lt;h3&gt;Memory&lt;/h3&gt;
&lt;p&gt;This shows the total amount of memory that is used as well as its usage, split into processes, system, binary, ets and code.&lt;/p&gt;
&lt;p&gt;The level that is considered normal, obviously depends on your situation. But when this suddenly goes up, it might be an indicator that something is wrong.&lt;/p&gt;
&lt;p&gt;For anything that&amp;#39;s monitored on a dashboard, you can set up triggers (which we call ‘anomaly detection’), that will message you via email/slack/PagerDuty when it goes over a normal value for your case, for a certain period. Our &lt;a href=&quot;https://docs.appsignal.com/anomaly-detection&quot;&gt;Documentation on Anomaly Detection&lt;/a&gt; describes how to set that up.&lt;/p&gt;
&lt;h2&gt;Dashboards for Host Metrics&lt;/h2&gt;
&lt;p&gt;Apart from the things that you are running in your Elixir setup, when you have AppSignal running, we also immediately add &lt;a href=&quot;https://docs.appsignal.com/metrics/host.html&quot;&gt;dashboards and metrics for your hosts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, check the ‘Host usage’ link in the Inspect menu item to see throughput, response time and queue time for any Namespace on that Host. And check the &amp;#39;Host Metrics&amp;#39; to see CPU, Disk usage, Load average and more for each of the Hosts.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ve seen that the integrated approach of monitoring really helps in narrowing down what causes issues. So for each of these metrics, you can click on a peak, check &amp;#39;what happened here&amp;#39; in the graph legend and see the entire overview of errors, performance issues and host metrics.&lt;/p&gt;
&lt;h2&gt;Edit or Extend as You Want&lt;/h2&gt;
&lt;p&gt;We always mix having loads of insight out-of-the-box with being able to tweak things exactly as you want. So if you want to have any of these dashboards set up differently, you can edit the dashboard configuration YAML and make it do exactly what you want.&lt;/p&gt;
&lt;h2&gt;What More Do You Want Us to Add?&lt;/h2&gt;
&lt;p&gt;We are always curious to hear what else you’d like us to set up Magic dashboards for. So if you have something in your Elixir setup that you want us to help visualize in a graph, drop us a line at &lt;a href=&quot;mailto:support@appsignal.com&quot;&gt;support@appsignal.com&lt;/a&gt;. We&amp;#39;ll then let everyone else have it magically.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;PS: Another hard part about monitoring is digesting the hundreds of billions of requests that you may emit. We might write a blog post about that another day ;-) It&amp;#39;s why we think you should use a dedicated service rather than run it yourself. And if you&amp;#39;d &lt;a href=&quot;https://www.appsignal.com/elixir/&quot;&gt;try us&lt;/a&gt; we&amp;#39;d be honored.&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>How to Get Your Elixir Application Ready for CI/CD</title>
    <link rel="alternate" href="https://blog.appsignal.com/2020/01/29/how-to-get-your-elixir-application-ready-for-ci-cd.html"/>
    <id>https://blog.appsignal.com/2020/01/29/how-to-get-your-elixir-application-ready-for-ci-cd.html</id>
    <published>2020-01-29T00:00:00+00:00</published>
    <updated>2020-01-29T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Explore a wide array of Elixir ecosystem tools that can help you create top-notch CI pipelines.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;This post was updated on 9 August 2023 with the latest software and package references, and updated screenshots.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In today&amp;#39;s post, we&amp;#39;ll go over what continuous integration and continuous delivery are, the benefits that come along with employing CI/CD, and some best practices that you should follow. We&amp;#39;ll also explore a wide array of Elixir ecosystem tools that can help you create top-notch CI pipelines. In order to experiment with a handful of the tools that we will be discussing, we&amp;#39;ll use a Git hooks Elixir library to execute our CI/CD validation steps, but on our local machine.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s jump right in!&lt;/p&gt;
&lt;h2&gt;What is CI/CD and When Do You Use It?&lt;/h2&gt;
&lt;p&gt;Continuous integration is the process by which new features and bug fixes are frequently merged into mainline branches. For every change to the code base, the project’s validation suite is executed to ensure it&amp;#39;s up to team standards and doesn&amp;#39;t introduce any regressions.&lt;/p&gt;
&lt;p&gt;Continuous delivery is the process by which validated code, once merged, generates a new build artifact. The build artifact with the new code is then automatically deployed to your non-production environments. Note that continuous delivery deploys to non-production environments. The act of deploying to production directly is called, confusingly enough, continuous deployment.&lt;/p&gt;
&lt;p&gt;CI and CD are critical tools to have at your disposal as they allow you and your team to move faster and with a higher degree of confidence. They enable you to catch bugs early on and ensure that they don&amp;#39;t impact customers.&lt;/p&gt;
&lt;h2&gt;How Does CI/CD Influence Application Design?&lt;/h2&gt;
&lt;p&gt;With the vocabulary explained, let&amp;#39;s move on to discussing &lt;a href=&quot;https://12factor.net/&quot; title=&quot;the 12 Factor App&quot;&gt;the 12 Factor App&lt;/a&gt;. This is a collection of techniques and guidelines that can be used to create sustainable and scalable web services. As the name implies, there are 12 concepts that make up the manifesto. For the purposes of CI/CD, we&amp;#39;ll focus on &amp;quot;Config&amp;quot; and &amp;quot;Codebase&amp;quot;, but I highly recommend reading up on the 12 Factor App if you are unfamiliar with it.&lt;/p&gt;
&lt;p&gt;The Codebase section states that a single code repository should contain only a single application. If your entire system is made up of multiple applications, then each of those applications should be contained within their own repositories. This is particularly relevant to CI/CD since, by following this convention, it is very easy to ensure that only the necessary applications are built, tested, and deployed. If multiple applications are contained within the same repository, it becomes a bit more difficult to ascertain which application should be built, tested, and deployed.&lt;/p&gt;
&lt;p&gt;The Config section states that any kind of configuration data, credentials and secrets need to be kept out of the code. Instead, these bits of data should be set in the application&amp;#39;s environment via environment variables. This is important from a CI/CD perspective since you will be able to spin up supporting services for testing, and can easily point your application to those services via runtime configuration. You can do this with a wide array of services such as Postgres, Redis and RabbitMQ. Not only will it make your application portable between higher up environments, but it will also make it easy to test.&lt;/p&gt;
&lt;h2&gt;CI/CD Best Practices&lt;/h2&gt;
&lt;p&gt;Before jumping into some Elixir ecosystem tooling, let&amp;#39;s review some best practices that we should adhere to when designing our CI/CD pipelines (for clarification, a CI/CD pipeline is defined as a series of steps that are performed in order to take code from commit to deployment):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure that your tests are deterministic, as having an unreliable suite of tests can have terrible consequences for the velocity of a team and the reliability of the software that is being validated.&lt;/li&gt;
&lt;li&gt;Run cheap validations first and expensive validations last so that the CI/CD pipeline fails as early as possible. You don&amp;#39;t want to take up CI/CD server resources running tests suites over and over again when you have other cheaper issues that need to be sorted out.&lt;/li&gt;
&lt;li&gt;Promote the same build artifact to higher-level environments as it gives you the greatest amount of confidence that what you tested is what you are deploying. By leveraging the Config philosophies from the 12 Factor App, it should be possible to promote the same build artifact by only changing some environment variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Elixir Tools for Continuous Integration&lt;/h2&gt;
&lt;p&gt;Luckily, there are many tools at our disposal that come out of the box with Elixir. Some of these tools include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mix compile --warnings-as-errors&lt;/code&gt; — Running this will return a non-zero exist status if your code contains any warnings.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mix xref unreachable --abort-if-any&lt;/code&gt; — Running this will return a non-zero exit status if your code makes any references to functions/modules that do no exist. If you are using Elixir 1.10+ this Mix task has been deprecated and its functionality has been rolled into &lt;code&gt;mix compile --warnings-as-errors&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mix xref deprecated --abort-if-any&lt;/code&gt; — Running this will return a non-zero exit status if your code leverages any functions that have been marked as deprecated. If you are using Elixir 1.10+ this Mix task has been deprecated and its functionality has been rolled into &lt;code&gt;mix compile --warnings-as-errors&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mix format --check-formatted&lt;/code&gt; — Running this will return a non-zero exist status if any of your source files do not adhere to the format configuration specified in your &lt;code&gt;.formatter.exs&lt;/code&gt;. This helps ensure that the codebase has a uniform look and feel for all team members.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mix test&lt;/code&gt; — Elixir has an amazing built-in testing framework called &lt;a href=&quot;https://hexdocs.pm/ex_unit/ExUnit.html&quot;&gt;ExUnit&lt;/a&gt;. By running the preceding command you can execute all of your project&amp;#39;s tests and the exit status will be non-zero if any tests failed.&lt;/li&gt;
&lt;/ul&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;After you&amp;#39;ve incorporated the aforementioned items into your CI flow, it is time to reach for some community tools. Luckily, the Elixir ecosystem is packed full of great tools! Below is a list of a few of the tools that I use day in and day out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rrrene/credo&quot;&gt;Credo&lt;/a&gt; is a configurable static analysis tool that checks your code for design, readability, and consistency issues. In addition, it also enforces its own style guide, which can help a codebase stay uniform even if there are many developers in and out of the code.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jeremyjh/dialyxir&quot;&gt;Dialyxir&lt;/a&gt; is an amazing static analysis tool that we inherit from Erlang. In order to streamline its usage in Elixir, the Dialyxir library provides a nice wrapper around Dialyzer, which makes it easier to consume from an Elixir perspective. If you make heavy usage of typespecs then this is a great tool for you to ensure that you aren&amp;#39;t introducing any type related errors into your code.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/akoutmos/doctor&quot;&gt;Doctor&lt;/a&gt; is a static analysis tool that focuses on scanning your project&amp;#39;s documentation. It can be used to enforce the presence of typespecs, function docs, and module docs. In addition, it can be configured to return a non-zero exit status if documentation coverage falls below a certain threshold.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/PSPDFKit-labs/bypass&quot;&gt;Bypass&lt;/a&gt; is a useful library for when you want to mock out external HTTP services for the purposes of your tests. Your mock server can be brought up during your tests and can return pre-canned responses.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/elixirs/faker&quot;&gt;Faker&lt;/a&gt; is an excellent library for when you need to generate fake data like names, address, phone numbers, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/thoughtbot/ex_machina&quot;&gt;ExMachina&lt;/a&gt; — If you leverage Ecto in your application and want a streamlined way of generating test data along with associations, then ExMachina is what you are looking for. When paired with Faker, ExMachina can make a great test data creation tool.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Elixir Tools for Continuous Delivery&lt;/h2&gt;
&lt;p&gt;Once your application has been tested and statically analyzed, you&amp;#39;ll want to deploy it somehow. Below are a few options that are available to you for doing so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/mix/Mix.Tasks.Release.html&quot;&gt;Mix Releases&lt;/a&gt; — As of Elixir 1.9, the ability to create self-contained application releases has been brought into Elixir core (historically, you would need to use separate tools like &lt;a href=&quot;https://github.com/bitwalker/distillery&quot;&gt;Distillery&lt;/a&gt;). Elixir is interesting from a deployment standpoint given that you have the ability to package your application and the Erlang virtual machine (the BEAM) all within a build artifact. You need to make sure that the machine you build on is the same as the machine that you deploy to, but seeing as the application+runtime are all bundled, you will not need Elixir or Erlang installed on the target machine.&lt;/li&gt;
&lt;li&gt;Docker — Like many programming languages available today, Elixir plays nicely with Docker and it is a relatively straightforward task to create a Docker image with your application. You can leverage the base Elixir Docker image and run your application via Mix inside the container for development purposes, or you can leverage &lt;a href=&quot;https://akoutmos.com/post/multipart-docker-and-elixir-1.9-releases/&quot;&gt;Mix Releases and multistage builds&lt;/a&gt; to create lightweight images with only your application and the bundled Erlang virtual machine.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/edeliver/edeliver&quot;&gt;eDeliver&lt;/a&gt; is a tool that can be used to deploy Elixir applications to remote hosts using hot-code upgrades. By using hot-code upgrades, you can update your application with zero downtime on one or more hosts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Performing CI Validations on Your Local Machine&lt;/h2&gt;
&lt;p&gt;In order to play around with some of the ideas presented here without trying to learn a new CI/CD system, we&amp;#39;ll instead experiment with validating a sample Elixir project using Git hooks. Leveraging Git hooks is a good habit to get into as it will help you validate your code locally before pushing it to your team&amp;#39;s repository. It makes fixing any errors easier, given that you don&amp;#39;t need to dig through logs to figure out why builds failed.&lt;/p&gt;
&lt;p&gt;To begin, start by cloning this sample repository:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-shell&quot;&gt;$ git clone https://github.com/iamaestimo/sample_math_updated
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once we have our project cloned locally, we&amp;#39;ll want to open up our &lt;code&gt;mix.exs&lt;/code&gt; file and add the following dependency:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    ...
    {:git_hooks, &amp;quot;~&amp;gt; 0.7.0&amp;quot;, only: [:dev], runtime: false}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, we can now open up our &lt;code&gt;config/config.exs&lt;/code&gt; file and add a few pre-commit checks.
Let&amp;#39;s start with one to check for code formatting:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;...

if Mix.env() != :prod do
  config :git_hooks,
    verbose: true,
    hooks: [
      pre_commit: [
        tasks: [
          {:cmd, &amp;quot;mix format --check-formatted&amp;quot;}
        ]
      ]
    ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go ahead and run a commit; in my case, I have intentionally left the &lt;code&gt;mix.exs&lt;/code&gt; file wrongly formatted so I can show you
what an error looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-08/mix-format-checks-failed.png&quot; alt=&quot;Mix format checks fail on commit&quot;/&gt;&lt;/p&gt;
&lt;p&gt;There is an issue with our project that requires fixing, specifically the formatting I&amp;#39;d mentioned earlier!
Luckily, our commit will not go through until we are able to rectify the issue. I&amp;#39;ll leave the fixing of issues in your capable hands.&lt;/p&gt;
&lt;p&gt;Next, let&amp;#39;s try something a bit different: using &lt;code&gt;doctor&lt;/code&gt; to do documentation checks. Open the &lt;code&gt;mix.exs&lt;/code&gt; file again and format it as shown below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Config

if Mix.env() != :prod do
  config :git_hooks,
    verbose: true,
    hooks: [
      pre_commit: [
        tasks: [
          {:cmd, &amp;quot;mix doctor&amp;quot;}
        ]
      ]
    ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this, go ahead and do another commit. In my case, I get the result below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-08/doctor-checks-pass.png&quot; alt=&quot;Doctor checks pass&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Finally, let&amp;#39;s see how we can use &lt;code&gt;Credo&lt;/code&gt; in the pre-commit checks. Again, open up &lt;code&gt;mix.exs&lt;/code&gt;, and edit it as below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;import Config

if Mix.env() != :prod do
  config :git_hooks,
    verbose: true,
    hooks: [
      pre_commit: [
        tasks: [
          {:cmd, &amp;quot;mix credo&amp;quot;}
        ]
      ]
    ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run a commit. Mine gives me a pass, as you can see below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2023-08/credo-checks.png&quot; alt=&quot;Credo commit checks&quot;/&gt;&lt;/p&gt;
&lt;p&gt;While we only performed the validation steps on our local machine, taking these same validation steps to an actual CI/CD pipeline is a relatively simple task. The Git hooks library that we leveraged allows us to run all of our configured steps via &lt;code&gt;mix git_hooks.run all&lt;/code&gt;. In other words, we can run this command in our CI/CD solution of choice and validate that our code changes pass team standards. The benefit of this is that our CI/CD validation steps can be easily run locally for quick and easy debugging.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Thanks for sticking with me to the end! Hopefully, you learned a thing or two related to CI/CD and how to go about doing it with an Elixir application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Top 10 AppSignal Blog Posts in 2019</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/12/17/top-10-appsigna-blog-posts-in-2019.html"/>
    <id>https://blog.appsignal.com/2019/12/17/top-10-appsigna-blog-posts-in-2019.html</id>
    <published>2019-12-17T00:00:00+00:00</published>
    <updated>2019-12-17T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Check out the most appreciated posts on our blog in 2019.</summary>
    <content type="html">&lt;p&gt;Hi there stroopwafel fans 👋&lt;/p&gt;
&lt;p&gt;As we&amp;#39;re looking forward to publishing more Ruby, Elixir, and JavaScript posts in the coming 2020, we decided to take a look back at the blog posts that you gave the most hearts on Twitter, reads on the blog, and that we got the most appreciation for in 2019.&lt;/p&gt;
&lt;h2&gt;1. &lt;a href=&quot;/2019/10/17/javascript-errors-an-exceptional-history.html&quot;&gt;JavaScript Errors: An Exceptional History&lt;/a&gt; ✨&lt;/h2&gt;
&lt;p&gt;Join us as we go through the origins and turbulent years of growth of JavaScript and see it grow into the language it is today.&lt;/p&gt;
&lt;h2&gt;2. &lt;a href=&quot;/2019/06/18/elixir-alchemy-building-go-with-phoenix-live-view.html&quot;&gt;Building and Playing the Go Game with Phoenix LiveView&lt;/a&gt; ⚗️&lt;/h2&gt;
&lt;p&gt;In this Elixir series, we built and played the Go game. The first part is all about implementing Go in Phoenix LiveView, and in the second part - &lt;a href=&quot;/2019/07/04/elixir-alchemy-building-go-in-elixir-time-travel-and-the-ko-rule.html&quot;&gt;Time Travel and the Ko Rule&lt;/a&gt;, we&amp;#39;ve added the ability to undo and redo moves and implement Go&amp;#39;s ko rule.&lt;/p&gt;
&lt;h2&gt;3. &lt;a href=&quot;/2019/03/26/object-marshalling-in-ruby.html&quot;&gt;Object Marshalling in Ruby&lt;/a&gt; 💎&lt;/h2&gt;
&lt;p&gt;In this article, we took a deep dive into object marshalling. Find out what it is, look at the Marshall module, and then go through an example. Then, go a step deeper and compare the &lt;code&gt;_dump&lt;/code&gt; and &lt;code&gt;self._load&lt;/code&gt; methods.&lt;/p&gt;
&lt;h2&gt;4. &lt;a href=&quot;/2019/04/30/ruby-magic-hidden-gems-delegator-forwardable.html&quot;&gt;Ruby&amp;#39;s Hidden Gems: Delegator and Forwardable&lt;/a&gt; 💎&lt;/h2&gt;
&lt;p&gt;In this exploration of Ruby&amp;#39;s standard library, we&amp;#39;ve looked at delegation through Ruby&amp;#39;s Delegator and Forwardable classes.&lt;/p&gt;
&lt;h2&gt;5. &lt;a href=&quot;/2019/04/02/background-processing-system-in-ruby.html&quot;&gt;Learning by Building a Background Processing System in Ruby&lt;/a&gt; 💎&lt;/h2&gt;
&lt;p&gt;We implemented a naive background processing system for fun! Learn some things along the way as a peek into the internals of popular background processing systems like Sidekiq.&lt;/p&gt;
&lt;h2&gt;6. &lt;a href=&quot;/2019/01/22/serving-plug-building-an-elixir-http-server.html&quot;&gt;Serving Plug: Building an Elixir HTTP Server From Scratch&lt;/a&gt; ⚗️&lt;/h2&gt;
&lt;p&gt;As we&amp;#39;re on a continuous quest to find out what’s happening under the hood, we took a deep dive into HTTP servers in Elixir.&lt;/p&gt;
&lt;h2&gt;7. &lt;a href=&quot;/2019/04/16/elixir-alchemy-routing-phoenix-umbrella-apps.html&quot;&gt;Routing in Phoenix Umbrella Apps&lt;/a&gt; ⚗️&lt;/h2&gt;
&lt;p&gt;Umbrella apps are an awesome way to structure Elixir projects. Behind the curtains, they are a very thin layer that just compiles everything to a single package. Instead of building a single large monolith, you can structure your code with multiple isolated contexts...&lt;/p&gt;
&lt;h2&gt;8. &lt;a href=&quot;/2019/01/08/ruby-magic-bindings-and-lexical-scope.html&quot;&gt;Bindings and Lexical Scope in Ruby&lt;/a&gt; 💎&lt;/h2&gt;
&lt;p&gt;In this winter episode, we’ll went into bindings and scopes. So put on your skis and follow us deep into the woods.&lt;/p&gt;
&lt;h2&gt;9. &lt;a href=&quot;/2019/02/05/ruby-magic-classes-instances-and-metaclasses.html&quot;&gt;Unraveling Classes, Instances and Metaclasses in Ruby&lt;/a&gt; 💎&lt;/h2&gt;
&lt;p&gt;Through examining metaclasses, learn how class and instance methods work in Ruby. Along the way, discover the difference between defining a method by passing an explicit “definee” and using &lt;code&gt;class &amp;lt;&amp;lt; self&lt;/code&gt; or &lt;code&gt;instance_eval&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;10. &lt;a href=&quot;/2019/07/09/productive-procrastination-for-programmers.html&quot;&gt;Productive Procrastination for Programmers - works for Ruby and Elixir&lt;/a&gt; 💎⚗️✨&lt;/h2&gt;
&lt;p&gt;We pushed this post until the very end of this list in a true procrastination fashion. This is a partly-ironic, not-so-serious post on productivity, but increased productivity might actually result from reading it. It is all about the sweetness of procrastination, of pushing away that task you dread, the proverbial frog you need to eat. Take it with a grain of salt.&lt;/p&gt;
&lt;h2&gt;Holiday Season is Approaching 🎊🎉🎄❄️&lt;/h2&gt;
&lt;p&gt;That was all for this roundup of favorite articles of 2019! The whole AppSignal team wishes you all the best for the coming year, with little errors, many amazing insights and even more amazing articles ☃️&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. Don&amp;#39;t forget to subscribe to our &lt;a href=&quot;/ruby-magic&quot;&gt;Ruby Magic&lt;/a&gt;, &lt;a href=&quot;/elixir-alchemy&quot;&gt;Elixir Alchemy&lt;/a&gt;, and &lt;a href=&quot;/javascript-sorcery&quot;&gt;JavaScript Sorcery&lt;/a&gt; newsletters!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to Use Broadway in Your Elixir Application</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/12/12/how-to-use-broadway-in-your-elixir-application.html"/>
    <id>https://blog.appsignal.com/2019/12/12/how-to-use-broadway-in-your-elixir-application.html</id>
    <published>2019-12-12T00:00:00+00:00</published>
    <updated>2019-12-12T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Discover how Broadway can help you create highly concurrent data processing pipelines in your Elixir app.</summary>
    <content type="html">&lt;p&gt;In today&amp;#39;s post, we will be covering the Elixir library named &lt;a href=&quot;https://github.com/plataformatec/broadway&quot;&gt;Broadway&lt;/a&gt;. This library is maintained by the kind folks at Plataformatec and allows us to create highly concurrent data processing pipelines with relative ease.&lt;/p&gt;
&lt;p&gt;After an overview of how Broadway works and when to use it, we&amp;#39;ll dive into a sample project where we&amp;#39;ll leverage Broadway to fetch temperature data from &lt;a href=&quot;https://openweathermap.org/&quot;&gt;https://openweathermap.org/&lt;/a&gt; in order to find the coldest city on earth. Our Broadway pipeline will loop over a list of all the cities in the world from a GenStage producer that we write.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s jump right in!&lt;/p&gt;
&lt;h2&gt;What Is Broadway and When Should You Use It in Your Elixir App?&lt;/h2&gt;
&lt;p&gt;Broadway allows us to create highly concurrent data processing pipelines largely due to how it is built on top of GenStage. GenStage is another Elixir library that is used to construct an event/message exchange between processes. Specifically, GenStage provides the features necessary to create coordinated producer and consumer processes and ensure that the event pipeline is never flooded. Consumers subscribe to upstream producers and demand messages when they are free to do work. With this model, we can scale the number of consumer processes as is needed for the task at hand to achieve the performance we desire.&lt;/p&gt;
&lt;h3&gt;Issues with Using GenStage in Production&lt;/h3&gt;
&lt;p&gt;A major problem with using GenStage directly for a production-grade application is that the onus is on the developer to create the proper supervision tree to ensure that failures are handled properly. This is exactly where Broadway comes into play. Broadway provides the necessary abstractions on top of GenStage that you would leverage in a production context such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Batching&lt;/li&gt;
&lt;li&gt;Ordering and partitioning&lt;/li&gt;
&lt;li&gt;Automatic restarts&lt;/li&gt;
&lt;li&gt;Graceful shutdowns&lt;/li&gt;
&lt;li&gt;Automatic message acknowledgment&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Additional Supporting Libraries&lt;/h3&gt;
&lt;p&gt;In addition to the aforementioned features, Broadway also has several supporting libraries that allow you to use a message queue service such as a Broadway producer (some are maintained by Plataformatec and some are community maintained). At the time of writing this post, there are &lt;a href=&quot;https://github.com/plataformatec/broadway#official-broadway-producers&quot;&gt;official Broadway Producers&lt;/a&gt; available for Amazon SQS, Google Pub/Sub and RabbitMQ. &lt;a href=&quot;https://github.com/plataformatec/broadway_kafka&quot;&gt;Support for Kafka&lt;/a&gt; is currently underway, but a release has not yet been cut for the project. The benefit of using Broadway Producers is that it abstracts away the problems that come along with managing a persistent and valid connection to the data source and provides a convenient way of using these data sources as the entry point into your data processing pipeline.&lt;/p&gt;
&lt;p&gt;All this is well and good, but when should you reach for a tool like Broadway?&lt;/p&gt;
&lt;p&gt;Broadway is a useful tool when the task at hand is &lt;a href=&quot;https://en.wikipedia.org/wiki/Embarrassingly_parallel&quot;&gt;embarrassingly parallel&lt;/a&gt; and spawning more processes yields positive results. It is also useful when you have an ETL (extract, transform and load) pipeline and want to break up the problem into discrete components and scale them independently. One example would be processing user image uploads. Increasing the number of workers will allow you to process more image uploads, and you can disconnect the image upload from the HTTP request/response cycle by leveraging a queuing system like RabbitMQ, SQS, etc.&lt;/p&gt;
&lt;h2&gt;How Does Broadway Work Internally?&lt;/h2&gt;
&lt;p&gt;As previously mentioned, Broadway leverages GenStage in order to orchestrate the event pipelines. If you look at the &lt;a href=&quot;https://github.com/plataformatec/broadway/blob/master/lib/broadway/producer.ex&quot;&gt;Broadway.Producer module&lt;/a&gt;, you&amp;#39;ll notice the line &lt;code&gt;use GenStage&lt;/code&gt; at the top. If you read further down into the module, you&amp;#39;ll find implementation for the &lt;code&gt;handle_subscribe/4&lt;/code&gt;, &lt;code&gt;handle_demand/2&lt;/code&gt;, &lt;code&gt;handle_cancel/3&lt;/code&gt;, and &lt;code&gt;handle_call/3&lt;/code&gt;, callbacks (to name a few) that are defined in the GenStage behavior. The magic of Broadway comes into play in how it automatically creates a supervision tree that ensures that your pipeline is fault-tolerant and reliable. Below is the supervision tree from the world temperature application that we will be writing shortly:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2019-12/supervision_tree.png&quot; alt=&quot;Sample application supervision tree&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s break the supervision tree down step by step. At the top of our tree, we have our project supervisor—&lt;code&gt;WorldTemp.Supervisor&lt;/code&gt;—which is defined in our &lt;code&gt;application.ex&lt;/code&gt; file. From there, we turn our focus to &lt;code&gt;WorldTemp.TempProcessor&lt;/code&gt; as that is the Broadway module that we&amp;#39;ll be creating (&lt;code&gt;WorldTemp.CityProducer&lt;/code&gt; and &lt;code&gt;WorldTemp.TempTracker&lt;/code&gt; are supporting GenServers). Further down the supervision tree, we get to &lt;code&gt;WorldTemp.TempProcessor.Broadway.Supervisor&lt;/code&gt;. This supervisor is responsible for monitoring all the various components of Broadway and restarting them if any errors occur. The processes that &lt;code&gt;WorldTemp.TempProcessor.Broadway.Supervisor&lt;/code&gt; supervises are listed below along with their purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WorldTemp.TempProcessor.Broadway.ProducerSupervisor&lt;/code&gt;: This supervisor is responsible for monitoring the data producer processes. This supervision tree has a strategy of &lt;code&gt;:one_for_one&lt;/code&gt; as it only needs to restart the particular data producer that is experiencing issues. All other producers can keep running if everything is okay.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WorldTemp.TempProcessor.Broadway.ProcessSupervisor&lt;/code&gt;: This supervisor is responsible for monitoring the worker processes that consume data from the producers. This supervision tree has a strategy of &lt;code&gt;:one_for_all&lt;/code&gt;. The reason that it&amp;#39;s not &lt;code&gt;:one_for_one&lt;/code&gt; is that the processing callback functions that we write should be stateless and any errors that occur can be handled without crashing the process. If an error does occur to crash the process, it is likely that some internal bookkeeping related to Broadway has gone awry and all the consumers need to be restarted.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WorldTemp.TempProcessor.Broadway.Terminator&lt;/code&gt;: This process is responsible for the proper stoppage of your Broadway pipeline. It will notify all the consumer processes that they should not resubscribe to producers once they terminate and it also notifies all the producers to flush all of their current events and ignore any subsequent data requests.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WorldTemp.TempProcessor.RateLimiter&lt;/code&gt;: This process is optionally started if your pipeline requires a rate limiter. It is effectively a &lt;a href=&quot;https://en.wikipedia.org/wiki/Token_bucket&quot;&gt;token bucket&lt;/a&gt; rate limiter and throttles how much work your processors can perform within a configurable time interval.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is also important to note that the &lt;code&gt;WorldTemp.TempProcessor.Broadway.Supervisor&lt;/code&gt; has a supervision policy of &lt;code&gt;:rest_for_one&lt;/code&gt;. The reason for this is that if the producer supervision tree crashes, the parent supervisor can restart all the subsequent supervision trees and restore the pipeline back to a working fresh state.&lt;/p&gt;
&lt;h2&gt;Hands-on with Broadway&lt;/h2&gt;
&lt;p&gt;As previously mentioned, we will be creating a very simple Broadway based application which will read weather data from an API and then keep a running record of the coldest city on earth. We will also be using a new feature of Broadway (rate limiting) to ensure that we don&amp;#39;t go over our free plan limit on &lt;a href=&quot;https://openweathermap.org&quot;&gt;https://openweathermap.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With that being said, let&amp;#39;s jump right in. Start by creating a new project using &lt;code&gt;mix new world_temp --sup&lt;/code&gt;. You&amp;#39;ll want to use the &lt;code&gt;--sup&lt;/code&gt; flag for convenience to set up the root application supervision tree. With your new project created, you want to change into the project directory and open up the &lt;code&gt;mix.exs&lt;/code&gt; file. Update the dependencies to look like the following (we&amp;#39;ll use my fork of Broadway as there is a pending issue with the rate limiter that I fixed in my fork):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defp deps do
  [
    {:httpoison, &amp;quot;~&amp;gt; 1.6&amp;quot;},
    {:jason, &amp;quot;~&amp;gt; 1.1&amp;quot;},
    {:broadway, github: &amp;quot;plataformatec/broadway&amp;quot;, tag: &amp;quot;08497708e10867935f2e92351e4cde9e4a57135e&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To fetch your dependencies, run &lt;code&gt;mix deps.get&lt;/code&gt; in your project directory. From there, we&amp;#39;ll want to create the file &lt;code&gt;lib/city_producer.ex&lt;/code&gt; which will act as the data producer for our Broadway pipeline. For the purposes of this sample project, this data producer will be a GenStage based module, but you can use the other Broadway producers if that better serves your needs (Kafka, RabbitMQ, SQS, etc). In the &lt;code&gt;lib/city_producer&lt;/code&gt; file, add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WorldTemp.CityProducer do
  use GenStage

  require Logger

  def start_link(_args) do
    GenStage.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init(_args) do
    {:producer, city_list()}
  end

  # If the demand is greater than the state of the GenState process,
  # readd the city list and reprocess
  def handle_demand(demand, state) when demand &amp;gt; length(state) do
    handle_demand(demand, state ++ city_list())
  end

  # Enough data is available in the GenStage&amp;#39;s state, serve that to
  # the consumer
  def handle_demand(demand, state) do
    {to_dispatch, remaining} = Enum.split(state, demand)

    {:noreply, to_dispatch, remaining}
  end

  # List of cities for which to get weather data
  defp city_list do
    [
      {&amp;quot;Abu Dhabi&amp;quot;, &amp;quot;United Arab Emirates&amp;quot;},
      {&amp;quot;Abuja&amp;quot;, &amp;quot;Nigeria&amp;quot;},
      {&amp;quot;Accra&amp;quot;, &amp;quot;Ghana&amp;quot;},
      {&amp;quot;Adamstown&amp;quot;, &amp;quot;Pitcairn Islands&amp;quot;},
      {&amp;quot;Addis Ababa&amp;quot;, &amp;quot;Ethiopia&amp;quot;},
      {&amp;quot;Algiers&amp;quot;, &amp;quot;Algeria&amp;quot;},
      {&amp;quot;Alofi&amp;quot;, &amp;quot;Niue&amp;quot;},
      ...
      # For full contents of this function go to Github project
      # https://github.com/akoutmos/world_temp
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Next, we&amp;#39;ll want to create a module that fetches weather data from the OpenWeatherMap API. You&amp;#39;ll want to go to &lt;a href=&quot;https://openweathermap.org/&quot;&gt;https://openweathermap.org/&lt;/a&gt; and create a free account to get an API key. Go ahead and create &lt;code&gt;lib/temp_fetcher.ex&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WorldTemp.TempFetcher do
  require Logger

  @api_key &amp;quot;YOU_API_KEY_GOES_HERE&amp;quot;

  def fetch_data(city, country) do
    city
    |&amp;gt; generate_url(country)
    |&amp;gt; HTTPoison.get()
    |&amp;gt; handle_response()
  end

  defp handle_response({:ok, %HTTPoison.Response{status_code: 200, body: body}}) do
    body
    |&amp;gt; Jason.decode!()
    |&amp;gt; get_in([&amp;quot;main&amp;quot;, &amp;quot;temp&amp;quot;])
  end

  defp handle_response(resp) do
    Logger.warn(&amp;quot;Failed to fetch temperature data: #{inspect(resp)}&amp;quot;)

    :error
  end

  defp generate_url(city, country) do
    &amp;quot;http://api.openweathermap.org/data/2.5/weather?q=#{city},#{country}&amp;amp;appid=#{@api_key}&amp;quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, we need to create our Broadway consumer module to leverage this HTTP API wrapper. Create &lt;code&gt;lib/temp_processor.ex&lt;/code&gt; with the following content. We&amp;#39;ll go over what it does shortly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WorldTemp.TempProcessor do
  use Broadway

  alias Broadway.Message

  def start_link(_opts) do
    Broadway.start_link(__MODULE__,
      name: __MODULE__,
      producer: [
        module: {WorldTemp.CityProducer, []},
        transformer: {__MODULE__, :transform, []},
        rate_limiting: [
          allowed_messages: 60,
          interval: 60_000
        ]
      ],
      processors: [
        default: [concurrency: 5]
      ]
    )
  end

  @impl true
  def handle_message(:default, message, _context) do
    message
    |&amp;gt; Message.update_data(fn {city, country} -&amp;gt;
      city_data = {city, country, WorldTemp.TempFetcher.fetch_data(city, country)}
      WorldTemp.TempTracker.update_coldest_city(city_data)
    end)
  end

  def transform(event, _opts) do
    %Message{
      data: event,
      acknowledger: {__MODULE__, :ack_id, :ack_data}
    }
  end

  def ack(:ack_id, _successful, _failed) do
    :ok
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;start_link/1&lt;/code&gt; function defines the various options required by Broadway to orchestrate the data pipeline. You&amp;#39;ll notice that the GenStage producer that we previously created is referenced in the producer keyword list section and we also defined a rate limiter to ensure that we don&amp;#39;t go over our free tier usage on OpenWeatherMap. The transformer entry invokes the &lt;code&gt;transform/2&lt;/code&gt; function at the bottom of the module which is required boilerplate to format our incoming messages to a &lt;code&gt;%Broadway.Message{}&lt;/code&gt; struct. An important thing to note here is that we specify 5 concurrent processors (if you recall from the supervision tree image earlier, there were 5 consumer processes). By changing that one value, you can determine how much concurrency/throughput you would like from your Broadway pipeline. The meat of our logic is in &lt;code&gt;handle_message/3&lt;/code&gt; where we retrieve our message (a city+country tuple), make an API call, and then update our rolling record of the coldest city.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s create that &lt;code&gt;WorldTemp.TempTracker&lt;/code&gt; module in &lt;code&gt;lib/temp_tracker.ex&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WorldTemp.TempTracker do
  use Agent

  def start_link(_) do
    Agent.start_link(fn -&amp;gt; nil end, name: __MODULE__)
  end

  def get_coldest_city do
    Agent.get(__MODULE__, fn {city, country, temp} -&amp;gt;
      &amp;quot;The coldest city on earth is currently #{city}, #{country} with a temperature of #{
        kelvin_to_c(temp)
      }°C&amp;quot;
    end)
  end

  def update_coldest_city(:error), do: nil

  def update_coldest_city({_, _, new_temp} = new_data) do
    Agent.update(__MODULE__, fn
      {_, _, orig_temp} = orig_data -&amp;gt;
        if new_temp &amp;lt; orig_temp, do: new_data, else: orig_data

      nil -&amp;gt;
        new_data
    end)
  end

  defp kelvin_to_c(kelvin), do: kelvin - 273.15
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This module is a relatively straight forward Agent-based module that allows us to retrieve the current coldest city, or update it if the provided value is lower than the currently set value.&lt;/p&gt;
&lt;p&gt;Lastly, we need to update our &lt;code&gt;lib/world_temp/application.ex&lt;/code&gt; file and add a couple of items to our supervision tree. If you named your modules the same as I did, your &lt;code&gt;application.ex&lt;/code&gt; file should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule WorldTemp.Application do
  @moduledoc false

  use Application

  alias WorldTemp.{CityProducer, TempProcessor, TempTracker}

  def start(_type, _args) do
    children = [
      TempTracker,
      CityProducer,
      TempProcessor
    ]

    opts = [strategy: :one_for_one, name: WorldTemp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all that in place, we can run &lt;code&gt;iex -S mix&lt;/code&gt; from the command line, and be able to interact with our application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(1) ▶ WorldTemp.TempTracker.get_coldest_city()
&amp;quot;The coldest city on earth is currently Bern, Switzerland with a temperature of 1.8100000000000023°C&amp;quot;
iex(2) ▶ WorldTemp.TempTracker.get_coldest_city()
&amp;quot;The coldest city on earth is currently Copenhagen, Denmark with a temperature of -0.37000000000000455°C&amp;quot;
iex(3) ▶ WorldTemp.TempTracker.get_coldest_city()
&amp;quot;The coldest city on earth is currently Copenhagen, Denmark with a temperature of -0.37000000000000455°C&amp;quot;
iex(4) ▶ WorldTemp.TempTracker.get_coldest_city()
&amp;quot;The coldest city on earth is currently Helsinki, Finland with a temperature of -1.8899999999999864°C&amp;quot;
iex(5) ▶ WorldTemp.TempTracker.get_coldest_city()
&amp;quot;The coldest city on earth is currently Roseau, Dominica with a temperature of -18.99999999999997°C&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By calling &lt;code&gt;WorldTemp.TempTracker.get_coldest_city()&lt;/code&gt; periodically, we can see that as the Broadway processors work through the city+country list, the city with the coldest temperature changes. It may take a few minutes to run through the whole list given that we are only processing 60 cities a minute and our list has a length of 216 elements.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;As we can see from the sample application that we&amp;#39;ve written, with relative ease, we were able to create a data processing pipeline for our Elixir application by using Broadway. With all of the abstractions given to us via Broadway, we can rest easy knowing that our pipeline will operate as intended and will recover from any issues if they arise. In addition, we have all the levers necessary to adjust the performance characteristics of our pipeline via some configuration.&lt;/p&gt;
&lt;p&gt;Thanks for sticking with me to the end and if you would like to learn more about Broadway, I suggest going through the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hexdocs.pm/broadway/Broadway.html&quot;&gt;Broadway behavior&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=IzFmNQGzApQ&quot;&gt;José Valim - Keynote: Announcing Brodway&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Guest author &lt;a href=&quot;https://akoutmos.com/top/about/&quot;&gt;Alex Koutmos&lt;/a&gt; is a Senior Software Engineer who writes backends in Elixir, frontends in VueJS and deploys his apps using Kubernetes. When he is not programming or blogging he is wrenching on his 1976 Datsun 280z.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. If you&amp;#39;d like to read Elixir Alchemy posts as soon as they get off the press, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to our Elixir Alchemy newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Caching with Elixir and ETS</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/11/12/caching-with-elixir-and-ets.html"/>
    <id>https://blog.appsignal.com/2019/11/12/caching-with-elixir-and-ets.html</id>
    <published>2019-11-12T00:00:00+00:00</published>
    <updated>2019-11-12T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Get started using ETS as a caching mechanism in your Elixir applications and pick up some useful tips and tricks.</summary>
    <content type="html">&lt;p&gt;In this post, you&amp;#39;ll learn how to use ETS as a caching mechanism in your Elixir applications, get familiar with different available options, and be made aware of some things to keep in mind.&lt;/p&gt;
&lt;h2&gt;The Concept of Caching&lt;/h2&gt;
&lt;p&gt;My two-year-old son loves eating cookies. He loves them so much that even while playing soccer, he keeps going back to the jar to grab one more.&lt;/p&gt;
&lt;p&gt;To stop playing so as to get another cookie is not something he enjoys, so he started grabbing multiple cookies and keeping them in his hands.&lt;/p&gt;
&lt;p&gt;That concept of keeping things that are important, but are costly to get, close to the subject that needs to use them, is commonly referred to as caching.&lt;/p&gt;
&lt;p&gt;In computing, caching is a ubiquitous concept that is used in both hardware and software. It has been around for a long time and is a smart concept, ported from real-life situations.&lt;/p&gt;
&lt;h2&gt;How Popular Languages Deal with Caching&lt;/h2&gt;
&lt;p&gt;Popular programming languages usually rely on external dependencies such as Memcache or Redis for caching. Using these tools is almost a standard practice now.&lt;/p&gt;
&lt;p&gt;Although that&amp;#39;s a valid approach, it introduces yet another dependency to a project. As simple as it initially seems, the operational costs of keeping that dependency alive (running, monitoring, patching with the latest security updates, etc.), might be overwhelming when the requirements are rather simple.&lt;/p&gt;
&lt;h2&gt;Cache in Elixir (and Erlang)&lt;/h2&gt;
&lt;p&gt;In Elixir, the need for caching information is common as a way of avoiding the unnecessary hurdle of accessing information that has a high-cost tag attached to it.&lt;/p&gt;
&lt;p&gt;Elixir comes with a huge advantage that might help simplify the lives of developers in need of caching—ETS.&lt;/p&gt;
&lt;p&gt;ETS stands for Erlang Term Storage. It enables developers to store and access data using a key.&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s a small example of the usage of an ETS table:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(4)&amp;gt; :ets.new(:security_level, [:named_table])
:security_level

iex(5)&amp;gt; :ets.insert(:security_level, {1, :high})
true

iex(6)&amp;gt; :ets.insert(:security_level, {2, :low})
true

iex(7)&amp;gt; :ets.insert(:security_level, {3, :none})
true

iex(8)&amp;gt; :ets.lookup(:security_level, 1)
[{1, :high}]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In that example, an ETS table named &lt;code&gt;:security_level&lt;/code&gt; is created, and a couple of values are inserted into it.&lt;/p&gt;
&lt;p&gt;ETS tables have four different types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Set&lt;/strong&gt;: That&amp;#39;s the default type—the one used in the above example. Each key can occur only once.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ordered set&lt;/strong&gt;: An ordered set has the same property as the set, but ordered by Erlang/Elixir term.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bag&lt;/strong&gt;: An ETS using the &amp;quot;bag&amp;quot; type supports multiple items per key.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Duplicate bag&lt;/strong&gt;: A &amp;quot;Duplicate bag&amp;quot; allows both duplicated keys and items.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The best ETS type to use depends on the specific needs of an application.&lt;/p&gt;
&lt;p&gt;The data structures used to implement the ETS tables in the Erlang VM are optimized to provide the best possible access time. Depending on the type, the Erlang VM uses either Hash Tables or Binary Trees to represent the ETS table. When compared to linear access times for a list, both cases have better performance.&lt;/p&gt;
&lt;p&gt;Here are two examples where I recently used ETS for caching purposes:&lt;/p&gt;
&lt;h3&gt;Feature Flags&lt;/h3&gt;
&lt;p&gt;We use continuous delivery at the company I work in, and feature flags are crucial if you&amp;#39;re doing trunk-based-development and want to integrate new, albeit not finished code, without enabling it for customers.&lt;/p&gt;
&lt;p&gt;We store our feature flags in &lt;a href=&quot;https://docs.aws.amazon.com/en_pv/systems-manager/latest/userguide/systems-manager-parameter-store.html&quot;&gt;AWS Parameter Store&lt;/a&gt;, fetching them once every 5 minutes and caching them locally in an ETS table.&lt;/p&gt;
&lt;h3&gt;Soft Real-Time Stats&lt;/h3&gt;
&lt;p&gt;There are several cases where we need to display things like &amp;quot;X people have purchased that plan&amp;quot; or &amp;quot;That product was already used by Y customers&amp;quot;.&lt;/p&gt;
&lt;p&gt;A naive approach would be to perform database queries every time such values are required, but that would be extremely heavy (and unnecessary) on our database.&lt;/p&gt;
&lt;p&gt;We cache those values and update them every couple of minutes. Although they might not reflect the real number, they indicate a &amp;quot;good enough&amp;quot; number, which is meaningful to customers.&lt;/p&gt;
&lt;h2&gt;Things to Keep in Mind When Using ETS as a Cache Solution&lt;/h2&gt;
&lt;h3&gt;Integration of Unnecessary Dependencies&lt;/h3&gt;
&lt;p&gt;ETS is part of the Erlang VM, so there are no additional dependencies necessary when using it.&lt;/p&gt;
&lt;h3&gt;Optimized Lookup&lt;/h3&gt;
&lt;p&gt;The lookup of an item (or group of items) is optimized depending on the type of the ETS table.&lt;/p&gt;
&lt;h3&gt;No Serialization&lt;/h3&gt;
&lt;p&gt;ETS tables can store Elixir data structures. This means you can store a group of &lt;code&gt;%Accounts.User{...}&lt;/code&gt; or &lt;code&gt;%PlayerScore{}&lt;/code&gt; and you&amp;#39;ll be able to fetch those structures back without having to serialize them.&lt;/p&gt;
&lt;h3&gt;Not Garbage Collected&lt;/h3&gt;
&lt;p&gt;When an ETS table is no longer necessary, you must delete it manually using &lt;code&gt;:ets.delete&lt;/code&gt;, otherwise, it might stay around forever.&lt;/p&gt;
&lt;p&gt;A common solution is to create a table inside a process (e.g. &lt;code&gt;GenServer&lt;/code&gt;). Since the ETS table is linked to the process that created it, if the process dies (or is terminated), the table also gets &amp;quot;garbage collected&amp;quot;.&lt;/p&gt;
&lt;h3&gt;Use of ETS in Distributed Systems&lt;/h3&gt;
&lt;p&gt;ETS plays nice when using distributed Elixir, but in both the examples I shared, the projects didn&amp;#39;t connect multiple nodes in a distributed Elixir fashion. Nevertheless, those features are part of a project deployed to several web servers, each one with its copy of ETS locally.&lt;/p&gt;
&lt;p&gt;In both examples—&amp;quot;Feature Flags&amp;quot; and &amp;quot;Soft real-time stats&amp;quot;—ETS works well because &lt;a href=&quot;https://en.wikipedia.org/wiki/Eventual_consistency&quot;&gt;Eventual Consistency&lt;/a&gt; is an acceptable side-effect.&lt;/p&gt;
&lt;h3&gt;How to Create and Use ETS Within a &lt;code&gt;GenServer&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Previously, I mentioned a case where I used ETS for &amp;quot;Feature Flags&amp;quot;. In this section, I want to give you a better understanding of its internals.&lt;/p&gt;
&lt;p&gt;The non-cached code is quite simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FeatureFlags do
  def enabled?(name) do
    name in get_list_of_enabled_flags()
  end

  defp get_list_of_enabled_flags() do
    # ... Access AWS, fetch values for specific project/env
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;FeatureFlags.enabled?/1&lt;/code&gt; returns either &lt;code&gt;true&lt;/code&gt; if the feature flag is enabled, or &lt;code&gt;false&lt;/code&gt; when it is not enabled.&lt;/p&gt;
&lt;p&gt;The problem with this code lies in the fact that for every call to &lt;code&gt;FeatureFlags.enabled?/1&lt;/code&gt;, the code performs requests to AWS and parses the response.&lt;/p&gt;
&lt;p&gt;Since the changes to the features happen once or twice a day, we can safely cache successful returns from AWS and use the cached version.&lt;/p&gt;
&lt;p&gt;What should we use for caching? If you guessed ETS, you&amp;#39;re right!&lt;/p&gt;
&lt;p&gt;Here&amp;#39;s the cached version:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FeatureFlags do
  use GenServer

  @table :features

  def start_link(_args) do
    GenServer.start_link(__MODULE__, nil, name: __MODULE__)
  end

  def is_enabled?(name) do
    :ets.lookup_element(@table, name, 2)
  rescue
    _ -&amp;gt; false
  end

  def init(nil) do
    for feature_name &amp;lt;- get_list_of_enabled_flags() do
      :ets.insert(@table, {feature_name, true})
    end

    {:ok, nil}
  end

  defp get_list_of_enabled_flags() do
    # ... Access AWS, fetch values for specific project/env
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first difference is the use of a &lt;code&gt;GenServer&lt;/code&gt;. As previously mentioned, ETS tables are not automatically garbage collected. When started by a &lt;code&gt;GenServer&lt;/code&gt;, the ETS will be garbage-collected together with the &lt;code&gt;GenServer&lt;/code&gt; process, in case it exists.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;init/1&lt;/code&gt;, we fetch all the features from AWS and insert them in the ETS table. The &lt;code&gt;init/1&lt;/code&gt; function is called only once. After that, all the requests to the &lt;code&gt;FeaturesFlags&lt;/code&gt; modules are going to use the cached version.&lt;/p&gt;
&lt;p&gt;(In that example, for simplicity reasons, we are not dealing with error handling or the update of the features).&lt;/p&gt;
&lt;p&gt;With our modified version, new calls to the &lt;code&gt;FeatureFlags.enabled?/1&lt;/code&gt; uses ETS to look up the values.&lt;/p&gt;
&lt;p&gt;You might be wondering: &amp;quot;But since you&amp;#39;re using a &lt;code&gt;GenServer&lt;/code&gt;, why not use the &lt;code&gt;GenServer&lt;/code&gt; state itself to hold the feature list instead?&amp;quot;.&lt;/p&gt;
&lt;p&gt;And that&amp;#39;s a totally valid point. The main reason behind that decision is that every call to access a &lt;code&gt;GenServer&lt;/code&gt; state (e.g. using &lt;code&gt;handle_call&lt;/code&gt; or &lt;code&gt;handle_cast&lt;/code&gt;), goes to the process mailbox and is processed serially. That&amp;#39;s the reason why &lt;code&gt;FeatureFlags.enabled?/1&lt;/code&gt; uses the ETS directly, not calling the &lt;code&gt;GenServer&lt;/code&gt; state.&lt;/p&gt;
&lt;p&gt;That approach achieves two essential points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It makes the ETS garbage collected by design and&lt;/li&gt;
&lt;li&gt;It achieves concurrency, by not serializing requests inside the &lt;code&gt;GenServer&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Developers building applications using Elixir are fortunate to have ETS available as part of the Erlang VM toolbelt.&lt;/p&gt;
&lt;p&gt;ETS provides a right mix of simplicity (removing the need for integrating yet another tool to a project) with performance (it&amp;#39;s a fast and battle-tested piece of software).&lt;/p&gt;
&lt;p&gt;Keep in mind that, like anything, ETS is not suitable for every caching problem. There are cases where ETS is not a good idea, and you need to rely on other tools to solve the problem, so take this content with a grain of salt and make sure ETS meets your needs before sticking to it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Typespecs and Behaviours in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/10/15/behaviours.html"/>
    <id>https://blog.appsignal.com/2019/10/15/behaviours.html</id>
    <published>2019-10-15T00:00:00+00:00</published>
    <updated>2019-10-15T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this post we talk about behaviours. Not ours. But Elixir&#039;s</summary>
    <content type="html">&lt;p&gt;Today, we will dive into Typespecs and Behaviours. These are two Elixir features that we are ecstatic (pun intended) about. They are great examples of built-in features in Elixir that help get some of the advantages of statically typed code.&lt;/p&gt;
&lt;h2&gt;Dynamically Typed with Features&lt;/h2&gt;
&lt;p&gt;Alright, let&amp;#39;s set the scene. Elixir is a dynamically typed language. This means that the type of each variable is not checked at compile-time, but rather at run-time. Like most things, this comes with advantages and disadvantages.&lt;/p&gt;
&lt;p&gt;The differences between statically and dynamically typed languages are sometimes the cause of heated debate, and there&amp;#39;s already a lot of material out there. &lt;a href=&quot;https://android.jlelse.eu/magic-lies-here-statically-typed-vs-dynamically-typed-languages-d151c7f95e2b&quot;&gt;This post&lt;/a&gt; provides a good comparison, and &lt;a href=&quot;https://blog.steveklabnik.com/posts/2010-07-17-what-to-know-before-debating-type-systems&quot;&gt;Chris Smith&amp;#39;s article&lt;/a&gt; is also a great dive into some of the fallacies that come when discussing type systems.&lt;/p&gt;
&lt;p&gt;Despite being dynamically-typed, Elixir does a pretty good job of providing some opt-in features to get some of the safety of statically typed languages. This is important because those features often provide important guarantees about your code. This is usually done by performing static analysis on your code and, with the help of the type system, catch mistakes early on.&lt;/p&gt;
&lt;p&gt;The two main examples of this are Typespecs and Behaviours.&lt;/p&gt;
&lt;h3&gt;Typespecs&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hexdocs.pm/elixir/typespecs.html&quot;&gt;Typespecs&lt;/a&gt; is an opt-in feature of Elixir that lets you annotate your functions to provide hints to the language as to what your function headers should look like. Like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  @spec bar(arg :: binary) :: number
  def bar(arg) do
    String.length(arg)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;@spec&lt;/code&gt; keyword lets you specify what the argument names and types should be, as well as the return type.&lt;/p&gt;
&lt;p&gt;This doesn&amp;#39;t cause any kind of compilation failure if the types don&amp;#39;t match (again, Elixir is dynamically typed, so the types aren&amp;#39;t actually enforced at compile-time). But it has two other main benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It allows for other tools to be built, which will perform static analysis on the code, and use these annotations to inform you if something looks wrong. &lt;a href=&quot;https://github.com/jeremyjh/dialyxir&quot;&gt;dialyxir&lt;/a&gt; is a popular tool for this;&lt;/li&gt;
&lt;li&gt;It serves as documentation so that anyone looking at your public API can clearly see what to expect.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Elixir provides a set of basic types that you can use in these specifications. &lt;code&gt;binary&lt;/code&gt;, &lt;code&gt;pid&lt;/code&gt; and &lt;code&gt;number&lt;/code&gt; are some of them (check the &lt;a href=&quot;https://elixir-lang.org/getting-started/basic-types.html&quot;&gt;official docs&lt;/a&gt; for more on this). But it also allows you to compose these basic types into more complex, custom ones, using the &lt;code&gt;@type&lt;/code&gt; directive:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  @type result :: {number, binary}

  @spec bar(arg :: binary) :: result
  def bar(arg) do
    {String.length(arg), arg}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Behaviours&lt;/h3&gt;
&lt;p&gt;Alright, now we take it to the next level and discuss behaviours. You can think of Behaviours as a kind of interface specification, like what you usually get in object-oriented languages.&lt;/p&gt;
&lt;p&gt;Behaviours allow you to specify a contract for your modules and force them to respond to a specific API. This allows you to decouple features, using adapter patterns and other such programming techniques to piece together your code.&lt;/p&gt;
&lt;p&gt;The upper layers of an application don&amp;#39;t really need to care if data is persisted into PostgreSQL, MongoDB, or some other database. That&amp;#39;s because Ecto provides a common language (API) to interact with adapters for these storage backends.&lt;/p&gt;
&lt;p&gt;A behaviour specifies a list of function headers, here called callbacks. Any other Elixir module which claims to implement said behaviour will have to define those callbacks and their implementation. If one is missing, a compiler warning will be issued, letting the programmer know something&amp;#39;s wrong.&lt;/p&gt;
&lt;p&gt;An example behaviour might look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Language do
  @callback greet(name :: binary) :: binary
  @callback thank :: binary
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This behaviour defines two function headers. These are defined just like you would a typespec, except that &lt;code&gt;@callback&lt;/code&gt; is used, instead of &lt;code&gt;@spec&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we can write some implementations of our language behaviour:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.English do
  def greet(name), do: &amp;quot;Hello, #{name}&amp;quot;
  def thank, do: &amp;quot;Thank you&amp;quot;
end

defmodule MyApp.Portuguese do
  def greet(_name), do: &amp;quot;TODO&amp;quot;
  def thank, do: &amp;quot;Obrigado&amp;quot;
end

defmodule MyApp.Japanese do
  def greet, do: &amp;quot;TODO&amp;quot;
  def thank, do: &amp;quot;TODO&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This last implementation will throw a warning because we&amp;#39;re failing to fulfill the contract. &lt;code&gt;greet&lt;/code&gt; should actually take an argument. And even if we don&amp;#39;t use it, we still need to expect it. &lt;code&gt;greet/0&lt;/code&gt; and &lt;code&gt;greet/1&lt;/code&gt; would be two different functions in Elixir, and the behaviour expects the latter.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;warning: function greet/1 required by behaviour MyApp.Language is not implemented (in module MyApp.Japanese)
  test.ex:20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that this is not a compilation failure, just a warning. These annotations are only meant to guide your development and warn you of &lt;em&gt;potential&lt;/em&gt; mistakes. It’s up to you to know what to do with them.&lt;/p&gt;
&lt;p&gt;But before looking into a real-life example of this, we need to discuss a pattern that is commonly associated with behaviours and interfaces...&lt;/p&gt;
&lt;h2&gt;The Adapter Pattern&lt;/h2&gt;
&lt;p&gt;The Adapter pattern is a well-known software development pattern, described in detail by the &lt;a href=&quot;https://www.goodreads.com/book/show/85009.Design_Patterns&quot;&gt;Gang of Four’s book on the subject&lt;/a&gt;. In short, it’s about building public interfaces within your code, such that pieces can be swapped with other functionally-equivalent pieces while keeping everything compatible.&lt;/p&gt;
&lt;p&gt;There are two main benefits to this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It promotes decoupling. By enforcing that modules only talk with other modules via the specified interfaces, it doesn’t matter what the underlying implementation is. As long as that part remains stable, inner refactors of your code can be made with a lot more confidence that compatibility won’t be broken&lt;/li&gt;
&lt;li&gt;It makes it easy to switch between multiple options. Ecto, as mentioned above, is a great example of this. While writing queries with it, you don’t really care if your backend is PostgreSQL, MongoDB, or something else. Ecto’s query language remains the same, and each adapter takes care of translating that to its own language.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As you may guess by now, the go-to way of creating adapters in Elixir is by using behaviours.&lt;/p&gt;
&lt;h2&gt;An Example Project&lt;/h2&gt;
&lt;p&gt;To demonstrate the usefulness of behaviours, I’ll take advantage of a real project for which I contributed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fun_with_flags&lt;/code&gt; is an awesome Elixir library for dealing with feature flags. It’s also one of the better-named projects out there&lt;/p&gt;
&lt;p&gt;Within my projects, I often felt the need to make feature flags known to my unit tests. Perhaps I’m writing tests to a disabled feature that hasn’t gone live yet, and therefore need to enable it in those tests, to trigger the correct code paths. Or perhaps I want to test how the program responds to different flag values (e.g.: rolling releases).&lt;/p&gt;
&lt;p&gt;Either way, I want the ability to enable/disable flags in tests. But the two existing adapters pose limitations to this. Spinning a Redis instance for my test suite seems too much. And using PostgreSQL would require setting up Ecto Sandbox, and giving up on &lt;code&gt;async: true&lt;/code&gt; completely for any related tests.&lt;/p&gt;
&lt;p&gt;The ideal scenario was to have all this run in memory. Which we can, thanks to the adapter pattern that was chosen.&lt;/p&gt;
&lt;h2&gt;An InMemory Adapter&lt;/h2&gt;
&lt;p&gt;And here we go. Everything folded together.&lt;/p&gt;
&lt;p&gt;The bulk of the work is to create a module that implements the &lt;a href=&quot;https://github.com/tompave/fun_with_flags/blob/67025a436e64795d78183024dc68e5022cd490ff/lib/fun_with_flags/store/persistent.ex&quot;&gt;&lt;code&gt;FunWithFlags.Store.Persistent&lt;/code&gt;&lt;/a&gt; behaviour. All functions listed in the behaviour (&lt;code&gt;worker_spec/0&lt;/code&gt;, &lt;code&gt;get/1&lt;/code&gt;, &lt;code&gt;put/1&lt;/code&gt;, &lt;code&gt;delete/1&lt;/code&gt;, &lt;code&gt;all_flags/0&lt;/code&gt; and &lt;code&gt;all_flag_names/1&lt;/code&gt;) need to be implemented in our adapter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule FunWithFlags.Store.Persistent.InMemory do
  @behaviour FunWithFlags.Store.Persistent
  # ...

  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, opts, name: opts: __MODULE__)
  end

  def init(_), do: {:ok, []}

  def get(flag_name) do
    GenServer.call(__MODULE__, {:get, flag_name})
  end

  def put(flag_name, gate) do
    GenServer.call(__MODULE__, {:put, flag_name, gate})
  end

  # ...

  def handle_call({:get, flag_name}, _from, state) do
    # ...
    # search for the given flag in the state, and return it&amp;#39;s status
  end

  def handle_call({:put, flag_name, gate}, _from, state) do
    # ...
    # insert the given gate into the current state
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This part of the implementation shows how the &lt;code&gt;get/1&lt;/code&gt; and &lt;code&gt;put/1&lt;/code&gt; functions are hooked up. The module is a GenServer to allow it to store and retrieve data without having to persist it to a database.&lt;/p&gt;
&lt;p&gt;Note that I avoided displaying the actual implementation of the various &lt;code&gt;handle_call/3&lt;/code&gt; functions because they’re rather bulky and already beside the point of this post. But the good news is, this is actually published as a hex package, and you can check it out on &lt;a href=&quot;https://github.com/naps62/fun_with_flags_in_memory&quot;&gt;Github&lt;/a&gt; too!&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Now we’ve gone all the way into the rabbit hole of this post, from theory to practice. From TypeSpecs, and how behaviours are a cool implementation of Adapter patterns in Elixir to the real-life example. We even got out at the other end on our best behaviour ;-)&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Flags, Seeds and Idempotency: Database Tooling with Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/09/10/flags-seeds-idempotency-elixir.html"/>
    <id>https://blog.appsignal.com/2019/09/10/flags-seeds-idempotency-elixir.html</id>
    <published>2019-09-10T00:00:00+00:00</published>
    <updated>2019-09-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this post, we stir into our cauldron of magic potions and idempotence, and brew some neat Elixir database tooling</summary>
    <content type="html">&lt;p&gt;Today we stir into our cauldron of magic potions and idempotence, and brew some neat Elixir database tooling. We&amp;#39;ll do so by going through my experience of setting up my own.&lt;/p&gt;
&lt;p&gt;Coming from Ruby on Rails, one of the things that I’ve seen lacking in the Elixir space when it comes to web applications is the helpful tooling that existed in the ecosystem to deal with databases in production. In this post, we’ll cover some of these and see how we can create similar tools in Elixir.&lt;/p&gt;
&lt;h2&gt;Customizing the Workflow When Setting up a Database&lt;/h2&gt;
&lt;p&gt;Most deployment solutions for Ruby on Rails would handle the setup of the database, tying directly into the way they are configured in the framework. This often included such things as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating and setting up the initial database&lt;/li&gt;
&lt;li&gt;Running all existing migrations&lt;/li&gt;
&lt;li&gt;Seeding the database&lt;/li&gt;
&lt;li&gt;Continuously running new migrations as they get added in future releases&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was all part of the ecosystem and was often taken for granted. But actually, there’s a lot of work involved in plugging all those things together. And sometimes, assumptions were made that made it difficult to tweak this flow to your particular needs.&lt;/p&gt;
&lt;p&gt;What if you have some kind of horizontal scaling on your application and need a more custom way to decide when and how migrations are executed? Or simply, what if you want to customize the order or the way each of these steps is done?&lt;/p&gt;
&lt;p&gt;The Ruby way of convention-over-configuration is pretty cool, especially when it comes to being a friendly environment for newcomers. But sometimes, the Elixir approach of explicitness has its benefits as well.&lt;/p&gt;
&lt;p&gt;With my latest projects, I ended up with some behavior where the ability to fully customize this workflow came in very handy. This ended up in a way that ensures our database is always in a ready state across deploys and even across database resets. Let&amp;#39;s dive into what we did and learned!&lt;/p&gt;
&lt;h2&gt;Running Migrations&lt;/h2&gt;
&lt;p&gt;As an introduction, let’s first see how migrations can be executed on Elixir. I’ll be using &lt;a href=&quot;https://github.com/bitwalker/distillery&quot;&gt;distillery releases&lt;/a&gt; to showcase this, but the process is pretty much translatable to any other Elixir/Erlang system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Migrator do
  def run do
    {:ok, _} = Application.ensure_all_started(:my_app)

    path = Application.app_dir(:my_app, &amp;quot;priv/repo/migrations&amp;quot;)

    Ecto.Migrator.run(MyApp.Repo, path, :up, all: true)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above module provides a function that executes migrations for a particular Repo in our application. Right from the start, we notice that all of this is very easily customizable since it’s pure Elixir code that we can change ourselves. Do you have two repos with different migration directories for each? Do you have an umbrella app with several repos spread across it? All of that can be handled here, according to your application’s needs.&lt;/p&gt;
&lt;p&gt;The above function is pretty much the equivalent of &lt;code&gt;mix ecto.migrate&lt;/code&gt;. But mix tasks aren’t available in Elixir releases, which is why we end up having to write them ourselves.&lt;/p&gt;
&lt;p&gt;To run this within our release, we can run this script as a start hook:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# rel/pre_start_hooks/10_migrate.sh

$RELEASE_ROOT_DIR/bin/my_app command Elixir.MyApp.Migrator run


# rel/config.exs

# ...

release :my_app do
 # ...

 set(pre_start_hooks: &amp;quot;rel/pre_start_hooks&amp;quot;)

 set(
   commands: [
     migrate: &amp;quot;rel/pre_start_hooks/10_migrate.sh&amp;quot;
   ]
 )
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These two additions to our Distillery setup will ensure that the migration function is called every time the application starts (which means, every time we deploy a new version). So migrations will end up running automatically as they’re deployed.&lt;/p&gt;
&lt;h2&gt;Seeding Your Database&lt;/h2&gt;
&lt;p&gt;Now that we have played around with migrations, let&amp;#39;s look into seeding your database. Usually, &lt;code&gt;mix seed&lt;/code&gt; will be used to insert initial records in your database. These are the records your app needs to function properly before your users get to it.&lt;/p&gt;
&lt;p&gt;This task just runs an Elixir script stored in &lt;code&gt;priv/repo/seeds.exs&lt;/code&gt;. But as we’ve seen, Mix tasks are not available within a release.&lt;/p&gt;
&lt;p&gt;Usually, your seeds file will consist of something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[&amp;quot;user&amp;quot;, &amp;quot;admin&amp;quot;, &amp;quot;editor&amp;quot;]
|&amp;gt; Enum.each(fn role -&amp;gt;
  MyApp.Role.new(name: role)
  |&amp;gt; MyApp.Repo.insert()
end)

MyApp.User.new(name: &amp;quot;Admin&amp;quot;, role: &amp;quot;admin&amp;quot;)
|&amp;gt; MyApp.Repo.insert()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To set this up within Distillery, I moved this logic into its own compiled module rather than an &lt;code&gt;.exs&lt;/code&gt; script:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.Seeds do
  def run do
    [&amp;quot;user&amp;quot;, &amp;quot;admin&amp;quot;, &amp;quot;editor&amp;quot;]
    |&amp;gt; Enum.each(fn role -&amp;gt;
      MyApp.Role.new(name: role)
      |&amp;gt; MyApp.Repo.insert()
    end)

    MyApp.User.new(name: &amp;quot;Admin&amp;quot;, role: &amp;quot;admin&amp;quot;)
    |&amp;gt; MyApp.Repo.insert()
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;priv/repo/seeds.exs&lt;/code&gt; script still exists, but it just calls the newly created function:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# priv/repo/seeds.exs

MyApp.Seeds.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, we’re ready to set it up as a Distillery pre-start hook.&lt;/p&gt;
&lt;p&gt;This is usually fine for local development, but if you’re setting this up as a pre-start hook, it means this script will be executed over and over again, after each new deploy. If you’re not careful, you may end up inserting duplicate seed data each time.&lt;/p&gt;
&lt;p&gt;One could solve this with some tricks that try and check if seeds were already run (such as setting a flag somewhere in the database and checking for it). But there’s a much more powerful way: Idempotent seeds.&lt;/p&gt;
&lt;h2&gt;Idempotent Seeds&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s get to the coolest stuff!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Idempotence&lt;/strong&gt; is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In short, an idempotent operation is one that you can harmlessly run multiple times, without fear of ending up with duplicate or accumulated results. For database seeds, ensuring their idempotency means you don’t need to worry about ending up with multiple admin users, for example.&lt;/p&gt;
&lt;p&gt;As it turns out, another very useful feature of moving seeds logic into a compiled module is the ability to unit-test them! Which is what I did:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.SeedsTest do
  use MyApp.DataCase, async: false

  test &amp;quot;creates an admin user&amp;quot; do
    MyApp.Seeds.run()

    assert admin = MyApp.Repo.one(MyApp.User)
    assert admin.role == &amp;quot;admin&amp;quot;
  end

  test &amp;quot;admin user creation is idempotent&amp;quot; do
    MyApp.Seeds.run()
    MyApp.Seeds.run()

    user_count = MyApp.Repo.aggregate(MyApp.User, :count, :id)
    assert user_count == 1
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first test ensures the seed does what it’s supposed to (in this case, the simple creation of a role in the database). The second one ensures that running the seeds twice doesn’t affect the final result.&lt;/p&gt;
&lt;p&gt;In a complex system where your codebase is constantly evolving, and the rest of your team is building features on top of other features, it’s common for someone to accidentally add changes that don’t behave as expected once they go live. It’s easy for a developer on your team to add a few new seeds, forgetting how that will play out in production. Let’s see a more practical example of this.&lt;/p&gt;
&lt;h2&gt;Seeding Feature Flags&lt;/h2&gt;
&lt;p&gt;One feature we rely a lot on is feature flags, which give us the ability to toggle behavior on and off without requiring a new release. In Elixir, I do this using the &lt;a href=&quot;https://github.com/tompave/fun_with_flags&quot;&gt;FunWithFlags package&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When a new flag is being added to the codebase, its initial value may not be too trivial to introduce. Are we adding a new feature, and therefore the flag should start out as &lt;code&gt;false&lt;/code&gt;? Or are we wrapping an existing feature around a flag, so that we can later remove or change it, in which case the flag should be &lt;code&gt;true&lt;/code&gt; by default, so as to preserve behavior?&lt;/p&gt;
&lt;p&gt;This may even change between environments. We may want certain flags to be enabled by default on our staging system but disabled in production until we manually enable them.&lt;/p&gt;
&lt;p&gt;This requirement ties in nicely with our ability to run seeds for our application in an idempotent way, check it out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.FlagsSeeds do
  def run do
    set_flag_if_not_set(:new_disabled_feature, false)
    if System.get_env(&amp;quot;ENV_NAME&amp;quot;) == &amp;quot;staging&amp;quot; do
      set_flag_if_not_set(:new_staging_feature, true)
    else
      set_flag_if_not_set(:new_staging_feature, false)
    end
  end

  defp set_flag_if_not_set(flag_name, value) do
    {:ok, existing} = FunWithFlags.all_flag_names()

    cond do
      Enum.member?(existing, flag_name) -&amp;gt;
        # flag already exists. skip operation
        nil

      value == true -&amp;gt;
        FunWithFlags.enable(flag_name)

      value == false -&amp;gt;
        FunWithFlags.disable(flag_name)

      true -&amp;gt;
        raise &amp;quot;Invalid flag value&amp;quot;
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this module, we’re able to programmatically define the initial value of our seeds, which can be dependent on some other factor, such as which environment we’re running in.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;set_flag_if_not_set/2&lt;/code&gt; function is the materialization of our idempotency requirement. We wouldn’t want a new release to disable a flag that we have already manually enabled, right?&lt;/p&gt;
&lt;p&gt;By first checking if the flag already exists, we ensure two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This flags module is idempotent since a second run will skip all flags&lt;/li&gt;
&lt;li&gt;It only works for unset flags, allowing us to manually set their values when needed, without fear of being overridden&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can get even fancier when testing this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyApp.FlagSeedsTest do
  use MyApp.DataCase, async: false

  test &amp;quot;is idempotent&amp;quot; do
    MyApp.FlagSeeds.run()
    current_flags = FunWithFlags.all_flags()

    MyApp.FlagSeeds.run()
    new_flags = FunWithFlags.all_flags()

    assert current_flags == new_flags()
  end

end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if I or someone else on my team wrongfully change the seeds file in a way that breaks idempotency, our test suite will catch that before it even reaches a live environment, saving everyone a lot of trouble.&lt;/p&gt;
&lt;h2&gt;Wave&lt;/h2&gt;
&lt;p&gt;We hope you enjoyed this little dive into some of the tooling we built, and that you&amp;#39;ve picked up some things you can use yourself. 👋&lt;/p&gt;
&lt;p&gt;If you want to get a regular dose of ⚗️Elixir Alchemy, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe&lt;/a&gt; to get the next episode of Alchemy delivered straight to your inbox.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Multiplayer Go with Elixir&#039;s Registry, PubSub and dynamic supervisors</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/08/13/elixir-alchemy-multiplayer-go-with-registry-pubsub-and-dynamic-supervisors.html"/>
    <id>https://blog.appsignal.com/2019/08/13/elixir-alchemy-multiplayer-go-with-registry-pubsub-and-dynamic-supervisors.html</id>
    <published>2019-08-13T00:00:00+00:00</published>
    <updated>2019-08-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In part 3 of building the Go Game in Elixir, we&#039;ll allow the creation of new games as well as inviting others to join in. Along the way, we touch on Elixir&#039;s Registry, PubSub and dynamic supervisors.</summary>
    <content type="html">&lt;p&gt;Welcome back to Elixir Alchemy, and to the third part in our series on implementing the Go game using Phoenix LiveView. In &lt;a href=&quot;/2019/06/18/elixir-alchemy-building-go-with-phoenix-live-view.html&quot;&gt;part one&lt;/a&gt;, we set up the game using LiveView and in &lt;a href=&quot;/2019/07/04/elixir-alchemy-building-go-in-elixir-time-travel-and-the-ko-rule.html&quot;&gt;part two&lt;/a&gt;, we added Game history and implemented the ko rule.&lt;/p&gt;
&lt;p&gt;Currently, our game is a local &amp;quot;hot seat&amp;quot; multiplayer game where players take turns on the same browser window. Our next adventure aims to turn the game into a true multiplayer experience by allowing players to play with others online.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;#39;ll take the first step towards that goal. We&amp;#39;ll allow the creation of new games as well as inviting others to join in by turning the Game struct into a dynamically supervised GenServer, we&amp;#39;ll keep track of games using Elixir&amp;#39;s Registry, we&amp;#39;ll allow players to connect to already started games, and we&amp;#39;ll broadcast moves to all connected players using &lt;code&gt;Phoenix.PubSub&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Where We Left Off&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/jeffkreeftmeijer/hayago/tree/starter-3&quot;&gt;starter app&lt;/a&gt; for this episode is where we left off last time. We have an implementation of the game with buttons to undo and redo moves.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/6bcd70d78c8949b82bd1f637786f0a19ceec87f1/12da1/videos/go2_5.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/4faf7dc0f4a4690a58c962bf589d7c8b5df98a11/86c0d/videos/go2_5.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/f44a2159e5e9685b2a7594cb946dc360ba682cfd/5de5c/videos/go2_5.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;p&gt;The &lt;a href=&quot;https://hayago.herokuapp.com&quot;&gt;final result&lt;/a&gt; can be played online, and the code for the completed application can be found in the repository&amp;#39;s &lt;a href=&quot;https://github.com/jeffkreeftmeijer/hayago/tree/master&quot;&gt;master branch&lt;/a&gt; (if you prefer to jump straight into the code).&lt;/p&gt;
&lt;p&gt;We have a lot to do, so let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Dynamically Supervised GenServers&lt;/h2&gt;
&lt;p&gt;Currently, the game&amp;#39;s state is kept in the player&amp;#39;s socket connection. This works for games with a single player, but there&amp;#39;s no way for another socket connection to access an existing game. To allow two players to play the game together over two socket connections, we need to store each started game in a separate process that both can access.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll use a dynamically supervised GenServer to keep each game&amp;#39;s state. The dynamic supervisor allows players to start games and it also automatically restarts them when a game process crashes.&lt;/p&gt;
&lt;p&gt;First, let&amp;#39;s turn our Game module into a GenServer to allow multiple processes to access it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...
  use GenServer

  def start_link(options) do
    GenServer.start_link(__MODULE__, %Game{}, options)
  end

  @impl true
  def init(game) do
    {:ok, game}
  end

  @impl true
  def handle_call(:game, _from, game) do
    {:reply, game, game}
  end

  @impl true
  def handle_cast({:place, position}, game) do
    {:noreply, Game.place(game, position)}
  end

  @impl true
  def handle_cast({:jump, destination}, game) do
    {:noreply, Game.jump(game, destination)}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our GenServer handles the &lt;code&gt;:game&lt;/code&gt; call, which returns the current game&amp;#39;s &lt;code&gt;Game&lt;/code&gt; struct. The &lt;code&gt;{:place, position}&lt;/code&gt; and &lt;code&gt;{:jump, destination}&lt;/code&gt; cast callbacks update the game by calling &lt;code&gt;Game.place/2&lt;/code&gt; and &lt;code&gt;Game.jump/2&lt;/code&gt;, respectively.&lt;/p&gt;
&lt;p&gt;With our GenServer callbacks in place, we can spawn a process that keeps a game&amp;#39;s state. To supervise these processes, we&amp;#39;ll use &lt;a href=&quot;https://hexdocs.pm/elixir/master/DynamicSupervisor.html&quot;&gt;Elixir&amp;#39;s &lt;code&gt;DynamicSupervisor&lt;/code&gt;&lt;/a&gt;, which allows spawning children on demand. We&amp;#39;ll use it to start a new game when a player opens the page.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/application.ex
defmodule Hayago.Application do
  # ...

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      HayagoWeb.Endpoint,
      {DynamicSupervisor, strategy: :one_for_one, name: Hayago.GameSupervisor}
    ]

    opts = [strategy: :one_for_one, name: Hayago.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll set up our dynamic supervisor in the app&amp;#39;s &lt;code&gt;Application&lt;/code&gt; module. The &lt;code&gt;:one_for_one&lt;/code&gt; strategy (which is the only one available for dynamic supervisors) ensures that a game is restarted whenever it crashes.&lt;/p&gt;
&lt;h2&gt;Pids, Atoms and the Registry&lt;/h2&gt;
&lt;p&gt;Because our Game module now implements GenServer callbacks, we can spawn a Game through the GenServer module.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% iex -S mix
iex(1)&amp;gt; {:ok, pid} = DynamicSupervisor.start_child(Hayago.GameSupervisor, Hayago.Game)
{:ok, #PID&amp;lt;0.286.0&amp;gt;}
iex(2)&amp;gt; GenServer.cast(pid, {:place, 0})
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The returned pid is used to get and update the game&amp;#39;s state. In this case, we use it to place a stone on the top-left position of the board.&lt;/p&gt;
&lt;p&gt;Instead of keeping the game in the socket for every connection, we could add the pid to the socket and then request and update its state through that.&lt;/p&gt;
&lt;p&gt;However, our supervisor is tasked with restarting any game process that crashes. When that happens, the game is restarted in a new process with a new pid. When that happens, the players will still be disconnected from the game because the only reference they have to the game will no longer be working, and they&amp;#39;ll have no way of getting the new pid.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(3)&amp;gt; Process.exit(pid, :kill)
true
iex(4)&amp;gt; Process.alive?(pid)
false
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;A solution to this is naming processes when they&amp;#39;re spawned so that we can refer to them by name. Whenever a named process is restarted by a supervisor, the newly started process automatically receives the name of the process it replaces.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(5)&amp;gt; {:ok, pid} = DynamicSupervisor.start_child(Hayago.GameSupervisor, {Hayago.Game, name: :game_1})
{:ok, #PID&amp;lt;0.285.0&amp;gt;}
iex(6)&amp;gt; Process.whereis(:game_1)
#PID&amp;lt;0.285.0&amp;gt;
iex(7)&amp;gt; Process.exit(pid, :kill)
true
iex(8)&amp;gt; Process.whereis(:game_1)
#PID&amp;lt;0.288.0&amp;gt;
iex(9)&amp;gt; GenServer.cast(pid, {:place, 0})
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we start a new game and use &lt;code&gt;:game_1&lt;/code&gt; as its name. If we kill the game process, another one is automatically spawned to replace it. The new process shares the same name, so we can continue using &lt;code&gt;:game_1&lt;/code&gt; to refer to the new process.&lt;/p&gt;
&lt;p&gt;This way, we could generate a unique name for each process when spawning it, and keep that in our socket to refer to the game later. But, wait! We&amp;#39;re naming our processes with atoms here. Since atoms aren&amp;#39;t garbage collected, spawning a lot of games can exhaust our memory. Instead, we&amp;#39;d like to use strings, which &lt;em&gt;are&lt;/em&gt; garbage collected.&lt;/p&gt;
&lt;p&gt;Because we can&amp;#39;t name a process with a string, we need to use a &lt;a href=&quot;https://hexdocs.pm/elixir/master/Registry.html&quot;&gt;Registry&lt;/a&gt; to link string names to game pids. Elixir&amp;#39;s GenServer implementation has a built-in way of referring to processes in a registry through it&amp;#39;s &lt;code&gt;:via&lt;/code&gt;-tuples. First, let&amp;#39;s start the registry in our main supervisor whenever the application starts.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/application.ex
defmodule Hayago.Application do
  # ...

  def start(_type, _args) do
    children = [
      HayagoWeb.Endpoint,
      {Registry, keys: :unique, name: Hayago.GameRegistry},
      {DynamicSupervisor, strategy: :one_for_one, name: Hayago.GameSupervisor}
    ]

    opts = [strategy: :one_for_one, name: Hayago.Supervisor]
    Supervisor.start_link(children, opts)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the new registry in place, we can start processes using a string as their name, and refer to them later without creating an atom for every spawned game.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(1)&amp;gt; {:ok, pid} = DynamicSupervisor.start_child(Hayago.GameSupervisor, {Hayago.Game, name: {:via, Registry, {Hayago.GameRegistry, &amp;quot;game_1&amp;quot;}}})
{:ok, #PID&amp;lt;0.294.0&amp;gt;}
iex(2)&amp;gt; Process.exit(pid, :kill)
iex(3)&amp;gt; GenServer.cast({:via, Registry, {Hayago.GameRegistry, &amp;quot;game_1&amp;quot;}}, {:place, 0})
:ok
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Switching to Game Processes&lt;/h2&gt;
&lt;p&gt;Instead of creating a new game struct and assigning it directly to the socket, we&amp;#39;ll update the &lt;code&gt;GameLive.mount/2&lt;/code&gt; function to start a supervised process that holds a game&amp;#39;s state.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def mount(_session, socket) do
    name =
      ?a..?z
      |&amp;gt; Enum.take_random(6)
      |&amp;gt; List.to_string()

    {:ok, _pid} =
      DynamicSupervisor.start_child(Hayago.GameSupervisor, {Game, name: via_tuple(name)})

    {:ok, assign_game(socket, name)}
  end

  # ...

  defp via_tuple(name) do
    {:via, Registry, {Hayago.GameRegistry, name}}
  end

  defp assign_game(socket, name) do
    socket
    |&amp;gt; assign(name: name)
    |&amp;gt; assign_game()
  end

  defp assign_game(%{assigns: %{name: name}} = socket) do
    game = GenServer.call(via_tuple(name), :game)
    assign(socket, game: game, state: Game.state(game))
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We create a random six-character string as the name of our process, which we use when spawning the process through our &lt;code&gt;GameSupervisor&lt;/code&gt;. The &lt;code&gt;via_tuple/1&lt;/code&gt; convenience function returns the &lt;code&gt;:via&lt;/code&gt;-tuple that we&amp;#39;ll need to register the process&amp;#39; name in the registry.&lt;/p&gt;
&lt;p&gt;Finally, we add an &lt;code&gt;assign_game/1-2&lt;/code&gt; function that takes a socket of the game&amp;#39;s registered name. It calls out to the GenServer process to get the game&amp;#39;s current state before assigning it to the socket.&lt;/p&gt;
&lt;p&gt;Next, we&amp;#39;ll switch both &lt;code&gt;handle_event/3&lt;/code&gt; variants to use the game via the GenServer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def handle_event(&amp;quot;place&amp;quot;, index, %{assigns: %{name: name}} = socket) do
    :ok = GenServer.cast(via_tuple(name), {:place, String.to_integer(index)})
    {:noreply, assign_game(socket)}
  end

  def handle_event(&amp;quot;jump&amp;quot;, destination, %{assigns: %{name: name}} = socket) do
    :ok = GenServer.cast(via_tuple(name), {:jump, String.to_integer(destination)})
    {:noreply, assign_game(socket)}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, we use the &lt;code&gt;via_tuple/1&lt;/code&gt; function to cast both our &lt;code&gt;:place&lt;/code&gt; and &lt;code&gt;:jump&lt;/code&gt; functions directly on the game&amp;#39;s process. We then reassign the game to the socket by calling our &lt;code&gt;assign_game/1&lt;/code&gt; function.&lt;/p&gt;
&lt;h2&gt;Multiplayer URL Sharing&lt;/h2&gt;
&lt;p&gt;To allow multiple players to connect to the same game, we&amp;#39;ll add the game&amp;#39;s name to a URL that the first user can share. When a user starts a new game, we&amp;#39;ll use the &lt;code&gt;pushState&lt;/code&gt; function from the HTML5 history API to add the game&amp;#39;s name to the URL without reloading the page.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll use Phoenix LiveView&amp;#39;s &lt;code&gt;live_redirect/2&lt;/code&gt; function for that⁠—which was added recently after we started working on the game. To make sure we&amp;#39;re on a recent enough version, let&amp;#39;s update the dependency before continuing.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;% mix deps.update phoenix_live_view
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a player visits the game without a game name in the URL, the app will start a new one and update the URL to include the newly created game&amp;#39;s name. In our case, the game is served on the root of our application, so visiting &lt;a href=&quot;http://localhost:4000&quot;&gt;http://localhost:4000&lt;/a&gt; will redirect to &lt;a href=&quot;http://localhost:4000?name=abcdef&quot;&gt;http://localhost:4000?name=abcdef&lt;/a&gt;, where &amp;quot;abcdef&amp;quot; is the game&amp;#39;s name.&lt;/p&gt;
&lt;p&gt;To do this, we&amp;#39;ll replace our &lt;code&gt;mount/2&lt;/code&gt; function with two variants of the &lt;code&gt;handle_params/3&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def handle_params(%{&amp;quot;name&amp;quot; =&amp;gt; name} = _params, _uri, socket) do
    {:noreply, assign_game(socket, name)}
  end

  def handle_params(_params, _uri, socket) do
    name =
      ?a..?z
      |&amp;gt; Enum.take_random(6)
      |&amp;gt; List.to_string()

    {:ok, _pid} =
      DynamicSupervisor.start_child(Hayago.GameSupervisor, {Game, name: via_tuple(name)})

    {:ok,
    live_redirect(
      socket,
      to: HayagoWeb.Router.Helpers.live_path(socket, HayagoWeb.GameLive, name: name)
    )}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first variant handles requests that have a name in the URL parameters. In that case, the latest game state is fetched from the process corresponding to the name from the parameters and assigned to the socket using the &lt;code&gt;assign_game/2&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;The second is a lot like the &lt;code&gt;mount/2&lt;/code&gt; function that we&amp;#39;re replacing. We&amp;#39;re generating a name and starting a game. However, instead of assigning the game to the socket and returning, this function uses LiveView&amp;#39;s &lt;code&gt;live_redirect/2&lt;/code&gt; function to add the name to the current URL. After the URL changes, the first variant is automatically executed, assigning the name and game state to the socket.&lt;/p&gt;
&lt;h2&gt;Broadcasting Moves to All Clients&lt;/h2&gt;
&lt;p&gt;If we open our game right now, we&amp;#39;ll see that every visit to &lt;a href=&quot;http://localhost:4000&quot;&gt;http://localhost:4000&lt;/a&gt; gets redirected to a URL with a name query parameter. Opening that URL twice connects two sockets to the same game.&lt;/p&gt;
&lt;p&gt;However, when a stone is placed in one of the windows, it doesn&amp;#39;t automatically appear in the other one. Only after refreshing the window do we see the correct placement of stones.&lt;/p&gt;
&lt;p&gt;Everything is wired up correctly, but the second socket isn&amp;#39;t getting notified when the first makes a move. We need a way to get all connected sockets to subscribe to a system that publishes updates to all clients when one makes a move.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll use &lt;code&gt;Phoenix.PubSub&lt;/code&gt; to make that happen. Back in our &lt;code&gt;GameLive&lt;/code&gt; module, we&amp;#39;ll subscribe each socket connection to a channel when a game is created, and then we&amp;#39;ll broadcast a message over that channel whenever we place a stone or travel in history.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def handle_params(%{&amp;quot;name&amp;quot; =&amp;gt; name} = _params, _uri, socket) do
    :ok = Phoenix.PubSub.subscribe(Hayago.PubSub, name)
    {:noreply, assign_game(socket, name)}
  end

  # ...

  def handle_event(&amp;quot;place&amp;quot;, index, %{assigns: %{name: name}} = socket) do
    :ok = GenServer.cast(via_tuple(name), {:place, String.to_integer(index)})
    :ok = Phoenix.PubSub.broadcast(Hayago.PubSub, name, :update)
    {:noreply, assign_game(socket)}
  end

  def handle_event(&amp;quot;jump&amp;quot;, destination, %{assigns: %{name: name}} = socket) do
    :ok = GenServer.cast(via_tuple(name), {:jump, String.to_integer(destination)})
    :ok = Phoenix.PubSub.broadcast(Hayago.PubSub, name, :update)
    {:noreply, assign_game(socket)}
  end

  def handle_info(:update, socket) do
    {:noreply, assign_game(socket)}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;handle_params/3&lt;/code&gt; (the variant that matches on URLs with name query parameters), we call out to &lt;code&gt;Phoenix.PubSub.subscribe/2&lt;/code&gt;. We use the game&amp;#39;s name as the channel&amp;#39;s topic. Because all connected clients will hit this function, we know they&amp;#39;ll all be subscribed to this topic.&lt;/p&gt;
&lt;p&gt;In both &lt;code&gt;handle_event/3&lt;/code&gt; functions, we use &lt;code&gt;Phoenix.PubSub.broadcast/3&lt;/code&gt; to send a message to all subscribers in the topic. We send &lt;code&gt;:update&lt;/code&gt; as the message, which is then picked up in a newly added &lt;code&gt;handle_info/2&lt;/code&gt; function, which fetches the current Game&amp;#39;s state and updates the view whenever it receives an update message.&lt;/p&gt;
&lt;p&gt;To make sure games are cleaned up, we need to terminate their processes when they&amp;#39;re no longer being used. For now, we&amp;#39;ll add a timeout to the GenServer&amp;#39;s callback functions. When a game hasn&amp;#39;t had any interaction for ten minutes, the process will send itself a &lt;code&gt;:timeout&lt;/code&gt; message to stop the process.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...
  use GenServer, restart: :transient

  @timeout 600_000

  def start_link(options) do
    GenServer.start_link(__MODULE__, %Game{}, options)
  end

  @impl true
  def init(game) do
    {:ok, game, @timeout}
  end

  @impl true
  def handle_call(:game, _from, game) do
    {:reply, game, game, @timeout}
  end

  @impl true
  def handle_cast({:place, position}, game) do
    {:noreply, Game.place(game, position), @timeout}
  end

  @impl true
  def handle_cast({:jump, destination}, game) do
    {:noreply, Game.jump(game, destination), @timeout}
  end

  @impl true
  def handle_info(:timeout, game) do
    {:stop, :normal, game}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By adding a timeout in milliseconds to every callback&amp;#39;s response tuple, we tell the GenServer to send itself a timeout message when the process hasn&amp;#39;t received a message for ten minutes. The &lt;code&gt;:timeout&lt;/code&gt; callback returns a &lt;code&gt;:stop&lt;/code&gt;-tuple to tell the process to stop.&lt;/p&gt;
&lt;p&gt;We also make sure to set the &lt;code&gt;:restart&lt;/code&gt; value to &lt;code&gt;:transient&lt;/code&gt; when including the GenServer code to ensure that the supervisor only restarts the game when it terminates abnormally.&lt;/p&gt;
&lt;h2&gt;What&amp;#39;s Next?&lt;/h2&gt;
&lt;p&gt;This concludes the third part on implementing the Go game in Phoenix. We&amp;#39;ve come quite a long way in implementing a true multiplayer game, and we&amp;#39;ve learned about Elixir&amp;#39;s dynamic supervisors, the Registry, and &lt;code&gt;Phoenix.PubSub&lt;/code&gt; along the way.&lt;/p&gt;
&lt;p&gt;In a future episode, we&amp;#39;ll continue turning our game into a multiplayer game by assigning each connection as a separate player by assigning each of them a color of stones on the board. See you then!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We&amp;#39;re hiring: ✍️ &lt;a href=&quot;https://www.appsignal.com/jobs/editor-in-chief&quot;&gt;(Remote) Editor in Chief @AppSignal ✏️&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>Metaprogramming: From C Preprocessing to Elixir Macros</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/07/16/elixir-alchemy-metaprogramming.html"/>
    <id>https://blog.appsignal.com/2019/07/16/elixir-alchemy-metaprogramming.html</id>
    <published>2019-07-16T00:00:00+00:00</published>
    <updated>2019-07-16T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Metaprogramming has come a long way since its early days. In this edition of Elixir Alcamy, we&#039;ll see how it evolved.</summary>
    <content type="html">&lt;p&gt;Developers have a love-hate relationship with metaprogramming. On the one hand, it’s a powerful tool to build reusable code. On the other hand, it can quickly become hard to understand and maintain.&lt;/p&gt;
&lt;p&gt;I like to think of it as salt. It’s pretty handy on many occasions, but use just a little too much of it, and you’re left with an unenjoyable dish.&lt;/p&gt;
&lt;p&gt;Also, large doses of either of them can lead to increased blood pressure. 😅&lt;/p&gt;
&lt;p&gt;However, metaprogramming has come a long way since it’s early days. While I still try not to overuse it, it’s become more useful and easy to work with. Let’s see how it evolved.&lt;/p&gt;
&lt;h1&gt;C/C++&lt;/h1&gt;
&lt;p&gt;If we go back a few decades, to a time when programming languages were more close to the metal, the C/C++ preprocessor was one of the only options we had to do something close to metaprogramming.&lt;/p&gt;
&lt;p&gt;This preprocessor was literally what the name suggests: A parser that would run through C code, and process specific definitions (keywords such as &lt;code&gt;#define&lt;/code&gt; and &lt;code&gt;#if&lt;/code&gt;), and would output a final version of the C code to the compiler. This final version could change based on some criteria. It would look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#define FOO 1

#if FOO == 1
#define MSG &amp;quot;Hello, World&amp;quot;
#else
#define MSG &amp;quot;Goodbye, World&amp;quot;
#endif

#include &amp;lt;stdio.h&amp;gt;

int main() {
  printf(MSG);
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This program would print &lt;code&gt;&amp;quot;Hello, World&amp;quot;&lt;/code&gt;, always. As you may guess, changing the FOO definition to 0, and re-compiling the program, would instead cause it to print &lt;code&gt;&amp;quot;Goodbye, World&amp;quot;&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;These preprocessor directives would often be used to create code targeting specific platforms or architectures. For example, you could set different behaviors for your program when compiled to target Windows systems than when targeting Linux systems. The two resulting binaries would have only the code that was relevant to that specific platform, and thus wouldn’t need to perform runtime checks for these conditions. These savings in storage and runtime performance could often be significant.&lt;/p&gt;
&lt;p&gt;However, if you have any C experience at all, you know how dangerous it is just in vanilla form. Now add a lot of preprocessing behavior on top of that, and it quickly becomes quite hard to manage. So it wouldn’t be advisable to use it for much more than small configurations, most of the time.&lt;/p&gt;
&lt;h1&gt;Ruby&lt;/h1&gt;
&lt;p&gt;With better technology and higher-level scripting languages, also came the possibility of creating more elaborate styles of programming. Particularly in Ruby, metaprogramming proved to be a powerful, yet scary feature.&lt;/p&gt;
&lt;p&gt;The way this works in Ruby is based on the idea that code is nothing more than a string of text, interpreted and executed by the Ruby environment.&lt;/p&gt;
&lt;p&gt;Since Ruby is interpreted at runtime, there’s no requirement of having the entire codebase compiled upfront. Ruby allows you to dynamically define instance methods on classes.&lt;/p&gt;
&lt;p&gt;Also, due to the way Ruby classes and instances are constructed internally, you can even define methods for individual instances rather than the entire class!&lt;/p&gt;
&lt;p&gt;PS: Further reading on Ruby Classes &lt;a href=&quot;https://www.devalot.com/articles/2008/09/ruby-singleton&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;class Foo
  def hello1
    puts &amp;quot;Hello from a regular method&amp;quot;
  end

  [:hello2, :hello3].each do |f|
    define_method f do
      puts &amp;quot;Hello from a dynamically-defined #{f} method&amp;quot;
    end
  end
end

foo = Foo.new

foo.define_singleton_method(:hello4) { puts &amp;quot;Hello only from this instance of Foo&amp;quot; }

foo.hello1
foo.hello2
foo.hello3
foo.hello4
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Ruby is also pretty lax when it comes to editing existing code, even from the standard library. This is valid Ruby:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;array = [1, 2, 3]

# will print out 3
puts array.size

class Array
  def size
    &amp;quot;Hello&amp;quot;
  end
end

# will now print out &amp;quot;Hello&amp;quot;
puts array.size
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Don’t to that, though! It will most likely break your program and is a bad practice overall.&lt;/p&gt;
&lt;p&gt;Last but not least, Ruby has some powerful ways of handling unexpected function calls, such as the &lt;code&gt;method_missing&lt;/code&gt; callback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;array = [1, 2, 3]

class Array
  def method_missing(method, *args)
    puts &amp;quot;#{method} method not found&amp;quot;

    if method == :sise then
      puts &amp;quot;Did you intend to type size instead?&amp;quot;
    end
  end
end

puts array.sise
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Overall, these abilities were a big game-changer for me when I first learned about them. It enabled me to think about my codebase in a whole new different way and improve it in the process.&lt;/p&gt;
&lt;p&gt;There were some issues, though. You know what they say: with great power comes great responsibility.&lt;/p&gt;
&lt;p&gt;Several Ruby libraries used and abused these metaprogramming mechanisms to create their own Domain Specific Languages. In the long run, this overuse would result in similar problems as we had in C++ times: difficulty maintaining and understanding a codebase.&lt;/p&gt;
&lt;p&gt;Elixir took, in my opinion, yet another step forward in the right direction here…&lt;/p&gt;
&lt;h1&gt;Elixir ❤️&lt;/h1&gt;
&lt;p&gt;Here, metaprogramming is built into the language’s core in a much more powerful way. Whereas Ruby allowed you to define methods dynamically, or event generate a string and evaluate it as code (the old &lt;code&gt;eval&lt;/code&gt; method that we all hate), Elixir allows you to mess with the Abstract Syntax Tree (AST) itself.&lt;/p&gt;
&lt;p&gt;This is done through the &lt;code&gt;quote&lt;/code&gt; keyword:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; expr = quote do
  &amp;quot;Hello, &amp;quot; &amp;lt;&amp;gt; &amp;quot;World&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trying out the above code, you’ll find that the string concat operation doesn’t get executed directly. Instead of a final string, you end up with an AST expression that describes your code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:&amp;lt;&amp;gt;, [context: Elixir, import: Kernel], [&amp;quot;Hello, &amp;quot;, &amp;quot;World&amp;quot;]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those familiar with &lt;a href=&quot;https://en.wikipedia.org/wiki/Polish_notation&quot;&gt;Polish Notation&lt;/a&gt; may quickly identify that this is equivalent to the string concatenation code from above. So by quoting some code, you get an AST description of that code, which you can then use across the rest of your codebase.&lt;/p&gt;
&lt;p&gt;You can then start to reason about your code as if it were a data structure (which it is… an AST), and perform operations to transform it:&lt;/p&gt;
&lt;p&gt;Let’s modify things a little bit:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; expr = quote do
  &amp;quot;Hello, &amp;quot; &amp;lt;&amp;gt; name
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now our expression uses a dynamic name instead. However, where does that name come from?
We don’t have that variable defined anywhere, but it is still syntactically correct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;{:&amp;lt;&amp;gt;, [context: Elixir, import: Kernel], [&amp;quot;Hello, &amp;quot;, {:name, [], Elixir}]}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, it will fail to execute, which we can test by using &lt;code&gt;Code.eval_quoted/3&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Code.eval_quoted(expr)
** (CompileError) nofile:1: undefined function name/0
    (elixir) lib/code.ex:590: Code.eval_quoted/3
    test.ex:5: (file)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s now create a second AST definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;definition = quote do
  name = &amp;quot;Miguel&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This second expression definition defines a variable called &lt;code&gt;name&lt;/code&gt;. However, remember, we’re not defining any value, just creating the AST for that operation.&lt;/p&gt;
&lt;p&gt;We can combine these two expressions into a single one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;final_code = quote do
  unquote(definition)
  unquote(expr)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ends up having the same result as if we had typed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;name = &amp;quot;Miguel&amp;quot;
&amp;quot;Hello, &amp;quot; &amp;lt;&amp;gt; name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, notice we never had to abandon the Elixir syntax and rules while doing so. We’re writing Elixir that writes Elixir!&lt;/p&gt;
&lt;p&gt;This is heavily used internally within Elixir’s core. Whenever you define a function, or a simple if statement, you’re executing macros that change the code’s AST according to fit your code into them. Speaking of which…&lt;/p&gt;
&lt;h2&gt;Elixir’s Macros&lt;/h2&gt;
&lt;p&gt;Much of Elixir’s features are written with macros. Many of the common operators you use can be rewritten with macros. Let’s take, for instance, the &lt;code&gt;unless&lt;/code&gt; operator (which already exists in the language’s core) and define it ourselves:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Foo do
  defmacro custom_unless(condition, do: do_clause, else: else_clause) do quote do
      if !unquote(condition) do
        unquote(do_clause)
      else
        unquote(else_clause)
      end
    end
  end

  defmacro custom_unless(condition, do: do_clause) do
    quote do
      Foo.custom_unless(unquote(condition), do: unquote(do_clause), else: nil)
    end
  end
end

defmodule Bar do
  require Foo

  Foo.custom_unless true, do: IO.puts(&amp;quot;not true&amp;quot;), else: IO.puts(&amp;quot;true&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our &lt;code&gt;custom_unless&lt;/code&gt; macro take in a boolean value. Inside, we check for the opposite of the condition (we run whatever code AST was given on that condition, and invert the resulting boolean). Then we execute the AST given for either the &lt;code&gt;do&lt;/code&gt; or the &lt;code&gt;else&lt;/code&gt; clause, depending on the result.&lt;/p&gt;
&lt;p&gt;However, the fun part about Elixir is that, since even the basic constructs such as &lt;code&gt;if&lt;/code&gt; clauses are often built using macros themselves, we can better embed our macros in the language. In other words, after defining our macro, this is also working Elixir code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Bar
  # importing instead of requiring allows us to call the macro directly,
  # without the Foo. prefix
  import Foo

  custom_unless true do
    IO.puts(&amp;quot;not true&amp;quot;)
  else
    IO.puts(&amp;quot;true&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This works because the interpretation of a multiline if/else block in Elixir is not much more than syntactic sugar for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;if condition do: something, else: something_else
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Hopefully, this has been a useful walkthrough of how macros evolved in the past, especially for Elixir developers that may not know the full power of their language, as well as the history.&lt;/p&gt;
&lt;p&gt;If you want to get a regular dose of ⚗️Elixir Alchemy, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe&lt;/a&gt; to get the next episode of Alchemy delivered straight to your inbox.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building the Go Game in Elixir - Time Travel and the Ko Rule</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/07/04/elixir-alchemy-building-go-in-elixir-time-travel-and-the-ko-rule.html"/>
    <id>https://blog.appsignal.com/2019/07/04/elixir-alchemy-building-go-in-elixir-time-travel-and-the-ko-rule.html</id>
    <published>2019-07-04T00:00:00+00:00</published>
    <updated>2019-07-04T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Today, we continue with our Go game to add the ability to undo and redo moves and implement Go&#039;s ko rule.</summary>
    <content type="html">&lt;p&gt;Welcome back to Elixir Alchemy! Two weeks ago, we started our adventure &lt;a href=&quot;/2019/06/18/elixir-alchemy-building-go-with-phoenix-live-view.html&quot;&gt;implementing the Go game in Elixir using Phoenix LiveView&lt;/a&gt;. Today, we return to the game to add the ability to undo and redo moves, then we&amp;#39;ll implement Go&amp;#39;s &lt;a href=&quot;https://senseis.xmp.net/?Ko&quot;&gt;ko&lt;/a&gt; rule.&lt;/p&gt;
&lt;h2&gt;Onward!&lt;/h2&gt;
&lt;p&gt;In this article we will mostly focus on the implementation of the game, but still learn about Phoenix LiveView on the way. The &lt;a href=&quot;https://hayago.herokuapp.com&quot;&gt;final result&lt;/a&gt; of today&amp;#39;s article includes undo and redo buttons, and the game prevents you from making moves that would revert the game to a previous state.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/jeffkreeftmeijer/hayago/tree/starter-2&quot;&gt;new starter app&lt;/a&gt; contains the result of the last episode, which is a Phoenix application that uses LiveView to render and update the board. It implements some of Go&amp;#39;s rules in its &lt;code&gt;State&lt;/code&gt; module and keeps track of each player&amp;#39;s captured stones. This time, we&amp;#39;ll add a &lt;code&gt;Game&lt;/code&gt; module that keeps the state of the whole game, including the previous moves.&lt;/p&gt;
&lt;p&gt;Prefer to skip ahead and read the code? The &lt;a href=&quot;https://github.com/jeffkreeftmeijer/hayago/tree/master&quot;&gt;master branch&lt;/a&gt; includes all the changes we&amp;#39;ll make in this episode, along with test coverage and thorough documentation of all functions.&lt;/p&gt;
&lt;h2&gt;Time travel preparations&lt;/h2&gt;
&lt;p&gt;Before we do some time traveling and let players undo and redo moves, the game needs to keep a history of the moves made since it started. Currently, it keeps one &lt;code&gt;State&lt;/code&gt; struct, which is accessible as &lt;code&gt;@state&lt;/code&gt; in the template.&lt;/p&gt;
&lt;p&gt;Whenever a player makes a move by clicking one of the invisible buttons on the board, the &lt;code&gt;GameLive&lt;/code&gt; module handles the event. It uses &lt;code&gt;State.place/2&lt;/code&gt; to create a new state struct and assigns that as the new state to update the view.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def handle_event(&amp;quot;place&amp;quot;, index, %{assigns: assigns} = socket) do
    new_game = Game.place(assigns.game, String.to_integer(index))
    {:noreply, assign(socket, game: new_game, state: Game.state(new_game))}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because of this implementation, there&amp;#39;s currently no way of jumping back in history, as our game replaces the state with each move, and forgets the previous state.&lt;/p&gt;
&lt;p&gt;To retain history, we&amp;#39;ll add a struct named &lt;code&gt;Game&lt;/code&gt;, which keeps a history of states in its &lt;code&gt;:history&lt;/code&gt; attribute. When the game starts, it has a single, empty state in its history list to represent the empty board.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  alias Hayago.{Game, State}
  defstruct history: [%State{}]

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#39;ll add a convenience function to get the current state from a game. The first state in the history list is always the current state, so we can take the list&amp;#39;s first element to get the current state.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...

  def state(%Game{history: [state | _]}) do
    state
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we&amp;#39;ll implement a &lt;code&gt;place/2&lt;/code&gt; function to the &lt;code&gt;Game&lt;/code&gt; module. It uses &lt;code&gt;State.place/2&lt;/code&gt; to create a new state struct, then prepends that to the history list.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...

  def place(%Game{history: [state | _] = history} = game, position) do
    %{game | history: [State.place(state, position) | history]}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&amp;#39;s use the new game struct in the &lt;code&gt;GameLive&lt;/code&gt; module. The &lt;code&gt;mount/2&lt;/code&gt; function is used to set up the game. Instead of creating a state struct and assigning it directly to the socket, we&amp;#39;ll create a new game struct and assign that to the &lt;code&gt;:game&lt;/code&gt; assign.&lt;/p&gt;
&lt;p&gt;We&amp;#39;ll still use the state struct in the template, so we&amp;#39;ll preload it in the live view by calling our new &lt;code&gt;Game.state/1&lt;/code&gt; function and assigning the result as &lt;code&gt;:state&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  alias Hayago.Game
  use Phoenix.LiveView

  # ...

  def mount(_session, socket) do
    game = %Game{}
    {:ok, assign(socket, game: game, state: Game.state(game))}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When placing a stone, we&amp;#39;ll now call the &lt;code&gt;Game.place/2&lt;/code&gt; function to update the current state while retaining the history list. Again, we use &lt;code&gt;Game.state/1&lt;/code&gt; on the updated game to preload the state.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  alias Hayago.Game
  use Phoenix.LiveView

  # ...

  def handle_event(&amp;quot;place&amp;quot;, index, %{assigns: assigns} = socket) do
    new_game = Game.place(assigns.game, String.to_integer(index))
    {:noreply, assign(socket, game: new_game, state: Game.state(new_game))}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we try the game again, we won&amp;#39;t see any changes. While we&amp;#39;re keeping the history of all moves, we aren&amp;#39;t doing anything with it yet.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/6b2730e8c7c1d1d5794ef0d7351b56026736d645/3aea1/videos/go2_1.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/6cd6e2f1efe35ff61bd92d861ed1abc110929383/2d956/videos/go2_1.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/afe9f67c1a932b62371d1c72d6e0f40a3ed1e945/15a4b/videos/go2_1.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;h2&gt;Time Travel&lt;/h2&gt;
&lt;p&gt;Although we&amp;#39;re now keeping a history of game states, all functions in our &lt;code&gt;Game&lt;/code&gt; module still only use the first state in the list. As each move prepends a state to the history list, the first in the list is always the latest state.&lt;/p&gt;
&lt;p&gt;To allow jumping back and forward, we&amp;#39;ll add an attribute named &lt;code&gt;:index&lt;/code&gt; to the &lt;code&gt;Game&lt;/code&gt; struct, which defaults to 0.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  alias Hayago.{Game, State}
  defstruct history: [%State{}], index: 0

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By having an index, we can jump back to a previous state without having to drop states from the front of the list. Instead, we&amp;#39;ll update our &lt;code&gt;state/1&lt;/code&gt; function to take the index into account. Instead of returning the first state in the list, it uses the game&amp;#39;s index to find the current state in the list.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...

  def state(%Game{history: history, index: index}) do
    Enum.at(history, index)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Now, if we have a game with a three-state history, setting the &lt;code&gt;:index&lt;/code&gt; attribute to 1 returns the second state in the list, essentially reverting to that state.&lt;/p&gt;
&lt;p&gt;To jump to a different index, we&amp;#39;ll add a convenience function called &lt;code&gt;jump/2&lt;/code&gt;, which overwrites a &lt;code&gt;Game&lt;/code&gt; struct&amp;#39;s &lt;code&gt;:index&lt;/code&gt; attribute.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Hayago.Game do
  # ...

  def jump(game, destination) do
    %{game | index: destination}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that our game module keeps a history of moves and we can jump between them, let&amp;#39;s add buttons to undo and redo moves when playing the game.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/templates/game/index.html.leex
# ...

&amp;lt;div class=&amp;quot;history&amp;quot;&amp;gt;
  &amp;lt;button phx-click=&amp;quot;jump&amp;quot; phx-value=&amp;quot;&amp;lt;%= @game.index + 1%&amp;gt;&amp;quot;&amp;gt;Undo&amp;lt;/button&amp;gt;
  &amp;lt;button phx-click=&amp;quot;jump&amp;quot; phx-value=&amp;quot;&amp;lt;%= @game.index - 1%&amp;gt;&amp;quot;&amp;gt;Redo&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use &amp;quot;jump&amp;quot; as the value for both buttons&amp;#39; &lt;code&gt;phx-click&lt;/code&gt; attributes, which is the name of a function we&amp;#39;ll implement shortly in the &lt;code&gt;GameLive&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;phx-value&lt;/code&gt; attribute is used to pass the history index we&amp;#39;d like to jump to. The history list reverses because new moves prepend to the history list. So to undo a move, we&amp;#39;ll increase the current index by 1, and we&amp;#39;ll decrease it by 1 to redo.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;GameLive&lt;/code&gt; module, we&amp;#39;ll handle the jump event by calling &lt;code&gt;Game.jump/2&lt;/code&gt; with the current game and the passed index, giving us a new game struct that we&amp;#39;ll assign on the socket. Like before, we update the state assign for convenience.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def handle_event(&amp;quot;jump&amp;quot;, destination, %{assigns: %{game: game}} = socket) do
    new_game = Game.jump(game, String.to_integer(destination))
    {:noreply, assign(socket, game: new_game, state: Game.state(new_game))}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we open our browser and navigate to &lt;a href=&quot;https://localhost:4000&quot;&gt;https://localhost:4000&lt;/a&gt;, we can see that the undo and redo buttons work. After placing a few stones, we can click the undo button to get the last one removed, and the redo button to get it back again.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/0334f97bcc2310639016b74b0d3505ef34b9706d/0a719/videos/go2_2.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/17a271178d2675b9fd938564c68e33ec88deb5eb/dc994/videos/go2_2.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/c87a286785dbe1039c5aad86ab190e3966824fbb/14b14/videos/go2_2.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;h2&gt;Branching off in History&lt;/h2&gt;
&lt;p&gt;However, if we undo a move and try to place a stone, we notice that the new stone doesn&amp;#39;t get added to the board. Instead, the stone we just removed by pressing the undo button reappears.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/36855dd8bb58265b47ba167e65689fd3ee9727a1/72fb9/videos/go2_3.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/5b51797ea6105234f9eb1268ccfd44b95e5f17e5/8bb4d/videos/go2_3.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/a5860692999bbfc3e3fc61b995ab19cfa5921423/ba20f/videos/go2_3.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;p&gt;It turns out we have one more step to take before we can place a new stone after pressing the undo button. Let&amp;#39;s break down what&amp;#39;s happening.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We place a stone on the board, which prepends a new state to the history list.&lt;/li&gt;
&lt;li&gt;We press the undo button to increase the history index to 1, bringing us back to our initial state, giving us an empty board again.&lt;/li&gt;
&lt;li&gt;We try to place a new stone, which prepends a new state to the history list. The Game&amp;#39;s index remains at 1.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The new state is the first in the list, meaning its index is 0, but the Game index is still 1. That index belongs to the move we&amp;#39;ve undone by pressing the undo button. Essentially, our newly added stones are delayed by one move.&lt;/p&gt;
&lt;p&gt;To fix this, we need to slice any undone states from the list whenever we add a new state by placing a new stone. Removing states from the history allows users to branch off in a different direction after undoing moves.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...

  def place(%Game{history: history, index: index} = game, position) do
    new_state =
      game
      |&amp;gt; Game.state()
      |&amp;gt; State.place(position)

    %{game | history: [new_state | Enum.slice(history, index..-1)], index: 0}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the new version of our &lt;code&gt;place/2&lt;/code&gt; function, we use &lt;code&gt;Enum.slice/2&lt;/code&gt; to drop the undone moves from the history list. We&amp;#39;ll also reset our game&amp;#39;s index attribute to 0, which makes sure our newly added stones always immediately appear. Now time travel works, though we are not sure whether this means we need to worry about avoiding the &lt;a href=&quot;https://www.quirkbooks.com/post/classic-time-travel-paradoxes-and-how-avoid-them&quot;&gt;predestination paradox&lt;/a&gt;.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/4594f479b0e2928fb2abbab479316668ef2a9f91/2937e/videos/go2_4.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/26127264936507654f9ff3b9148385c2aeab0366/577e7/videos/go2_4.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/04be24964bbd50a34b934cdfe62d6f684aebb937/ad408/videos/go2_4.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;h2&gt;Disabling Inapplicable Undo and Redo Buttons&lt;/h2&gt;
&lt;p&gt;Now when there are no moves to undo or redo, we need to make sure the undo and redo buttons are disabled. To do that, we&amp;#39;ll implement a function named &lt;code&gt;history?/2&lt;/code&gt;, which takes a game struct and an index and returns whether that index is part of the game&amp;#39;s history.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...

  def history?(%Game{history: history}, index) when index &amp;gt;= 0 and length(history) &amp;gt; index do
    true
  end

  def history?(_game, _index), do: false
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our function checks if the requested index is above 0 to make sure the game doesn&amp;#39;t allow jumping forward when there are no moves done yet. Then, it checks if the length of the history list is higher than the index, to make sure we don&amp;#39;t overshoot the list when undoing moves.&lt;/p&gt;
&lt;p&gt;With our new function in place, we can check if the game can undo and redo to the previous and next move before rendering the button. If it can&amp;#39;t, it renders a disabled version.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/templates/game/index.html.leex
&amp;lt;div class=&amp;quot;history&amp;quot;&amp;gt;
  &amp;lt;%= if Hayago.Game.history?(@game, @game.index + 1) do %&amp;gt;
    &amp;lt;button phx-click=&amp;quot;jump&amp;quot; phx-value=&amp;quot;&amp;lt;%= @game.index + 1%&amp;gt;&amp;quot;&amp;gt;Undo&amp;lt;/button&amp;gt;
  &amp;lt;% else %&amp;gt;
    &amp;lt;button disabled=&amp;quot;disabled&amp;quot;&amp;gt;Undo&amp;lt;/button&amp;gt;
  &amp;lt;% end %&amp;gt;

  &amp;lt;%= if Hayago.Game.history?(@game, @game.index - 1) do %&amp;gt;
    &amp;lt;button phx-click=&amp;quot;jump&amp;quot; phx-value=&amp;quot;&amp;lt;%= @game.index - 1%&amp;gt;&amp;quot;&amp;gt;Redo&amp;lt;/button&amp;gt;
  &amp;lt;% else %&amp;gt;
    &amp;lt;button disabled=&amp;quot;disabled&amp;quot;&amp;gt;Redo&amp;lt;/button&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trying the game again, we&amp;#39;ll see that we can&amp;#39;t undo further than the list of previous moves, and we can&amp;#39;t redo into the future.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/6bcd70d78c8949b82bd1f637786f0a19ceec87f1/12da1/videos/go2_5.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/4faf7dc0f4a4690a58c962bf589d7c8b5df98a11/86c0d/videos/go2_5.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/f44a2159e5e9685b2a7594cb946dc360ba682cfd/5de5c/videos/go2_5.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;h2&gt;The Ko Rule&lt;/h2&gt;
&lt;p&gt;Aside from allowing the player to undo and redo moves, keeping history allows us to implement Go&amp;#39;s ko rule.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A play is illegal if it would have the effect (after all steps of the play have been completed) of creating a position that has occurred previously in the game.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Go prevents players from making moves that revert the board to a previous state. In practice, this happens when a player captures a stone, and the other player makes a move that immediately captures the newly added stone.&lt;/p&gt;
&lt;p&gt;Currently, we validate moves in the &lt;code&gt;State.legal?/2&lt;/code&gt; function, which checks if a position is empty, and makes sure placing a stone on that position has liberties.&lt;/p&gt;
&lt;p&gt;To implement the ko rule, we need the history of game states, meaning we need access to the &lt;code&gt;Game&lt;/code&gt; struct. To do that, we add a function named &lt;code&gt;Game.legal?/2&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/game.ex
defmodule Hayago.Game do
  # ...

  def legal?(game, position) do
    State.legal?(Game.state(game), position) and not repeated_state?(game, position)
  end

  defp repeated_state?(game, position) do
    %Game{history: [%State{positions: tentative_positions} | history]} =
      Game.place(game, position)

    Enum.any?(history, fn %State{positions: positions} -&amp;gt;
      positions == tentative_positions
    end)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our new function takes the game struct as its first argument and the position a new stone is placed as the second. It calls &lt;code&gt;State.legal?/2&lt;/code&gt; to make sure the already-implemented rules are satisfied. Then, it makes sure the new state hasn&amp;#39;t already happened using &lt;code&gt;repeated_state?/2&lt;/code&gt;, a private function that places the stone and compares the new state to the history list.&lt;/p&gt;
&lt;p&gt;Finally, we&amp;#39;ll update the template to switch from using &lt;code&gt;State.legal?/2&lt;/code&gt; directly to using &lt;code&gt;Game.legal?/2&lt;/code&gt;, which takes the game history into account.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/templates/game/index.html.leex
# ...

&amp;lt;div class=&amp;quot;board &amp;lt;%= @state.current %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;%= for {value, index} &amp;lt;- Enum.with_index(@state.positions) do %&amp;gt;
    &amp;lt;%= if Hayago.Game.legal?(@game, index) do %&amp;gt;
      &amp;lt;button phx-click=&amp;quot;place&amp;quot; phx-value=&amp;quot;&amp;lt;%= index %&amp;gt;&amp;quot; class=&amp;quot;&amp;lt;%= value %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;
    &amp;lt;% else %&amp;gt;
      &amp;lt;button class=&amp;quot;&amp;lt;%= value %&amp;gt;&amp;quot; disabled=&amp;quot;disabled&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;

# ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Back in the game, we&amp;#39;ll see that we can&amp;#39;t make a move that reverts the game&amp;#39;s state to one that&amp;#39;s in the history anymore.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/938ebba0bfb72a245148fed9b94129ed26b0b2ba/4c699/videos/go2_6.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/13f0249dd83bc9094ca9e5e4791aa7471a3e72f2/c8f65/videos/go2_6.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/359bef021c875f713dcf9241310245ca444c444d/dc9da/videos/go2_6.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;h2&gt;Time travel and the ko rule&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve improved our game by adding a smart way to revert moves, and through that, we were able to implement the Ko rule. Along the way, we&amp;#39;ve learned how flexible LiveView is, as we hardly touched the live view code, although we&amp;#39;ve changed quite a bit in the game.&lt;/p&gt;
&lt;p&gt;This concludes part two of our series on implementing the Go game with Elixir and Phoenix LiveView. We&amp;#39;d love to know how you&amp;#39;re enjoying it so far, and what you&amp;#39;d like to learn about next.&lt;/p&gt;
&lt;p&gt;If you want to have this article in your inbox as soon as it appears, travel back in time and &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to the Elixir Alchemy list&lt;/a&gt;. Until next time, and in the meantime, be careful with your newfound time travel abilities!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building and Playing the Go Game with Phoenix LiveView</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/06/18/elixir-alchemy-building-go-with-phoenix-live-view.html"/>
    <id>https://blog.appsignal.com/2019/06/18/elixir-alchemy-building-go-with-phoenix-live-view.html</id>
    <published>2019-06-18T00:00:00+00:00</published>
    <updated>2019-06-18T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Today we play the Go game. But we implement it in Phoenix LiveView first.</summary>
    <content type="html">&lt;p&gt;Welcome back to another Elixir Alchemy! This time, we&amp;#39;ll discover the power of &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view&quot;&gt;Phoenix LiveView&lt;/a&gt; by building an interactive game.&lt;/p&gt;
&lt;p&gt;By rendering HTML on the server and communicating between the frontend and backend over web sockets, LiveView helps us build real-time interfaces without writing JavaScript or worrying about updating the state in the browser. By updating the state on the server side, LiveView makes sure to only update the parts of the page that need to be, resulting in fast applications that send minimal amounts of data over the wire.&lt;/p&gt;
&lt;p&gt;To illustrate this, we’ll build our game in Phoenix, and we’ll use LiveView to make it interactive. Although tic-tac-toe is fun, we’ll go for something a bit more ambitious by building &lt;a href=&quot;https://en.wikipedia.org/wiki/Go_(game)&quot;&gt;Go&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Go is an abstract strategy board game for two players, in which the aim is to surround more territory than the opponent. The game was invented in China more than 2,500 years ago and is believed to be the oldest board game continuously played to the present day.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href=&quot;https://hayago.herokuapp.com&quot;&gt;final result&lt;/a&gt; is an implementation of the Go game that allows players to take turns placing stones on the board. Players can capture each other&amp;#39;s stones, and the game keeps track of which stones were captured.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2019-06/go.png&quot; alt=&quot;The Go game, implemented with Phoenix LiveView&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Along the way, we’ll learn how &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view&quot;&gt;Phoenix LiveView&lt;/a&gt; can help you build interactive applications without duplicating code between the frontend and the backend by keeping everything in Elixir.&lt;/p&gt;
&lt;h2&gt;Let’s Go!&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/jeffkreeftmeijer/hayago/tree/starter&quot;&gt;starter app&lt;/a&gt; is a Phoenix application with some parts already set up. The master branch holds the &lt;a href=&quot;https://github.com/jeffkreeftmeijer/hayago/tree/master&quot;&gt;source code&lt;/a&gt; for the completed project, if you&amp;#39;d prefer to skip ahead.&lt;/p&gt;
&lt;p&gt;The starter app cleans up some generated files, adds styling for the Go board, pre-installs Phoenix LiveView according to the install guide in the &lt;a href=&quot;https://github.com/phoenixframework/phoenix_live_view/tree/108c96aca0245fa673307f0e1a617f4b0704e981#readme&quot;&gt;README&lt;/a&gt;, and has a module that keeps track of the game’s state.&lt;/p&gt;
&lt;p&gt;In our game, the &lt;code&gt;State&lt;/code&gt; module describes the state of the game. The starter app already comes with the &lt;code&gt;State&lt;/code&gt; module so we can focus on working with LiveView.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;State&lt;/code&gt; struct keeps track of which stones are on the board in its &lt;code&gt;:positions&lt;/code&gt; list, and it knows which player is up next in its &lt;code&gt;:current&lt;/code&gt; key.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago/state.ex
defmodule Hayago.State do
  alias Hayago.State
  defstruct positions: Enum.map(1..81, fn _ -&amp;gt; nil end), current: :black

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A newly created state is initialized with list of 81 &lt;code&gt;nil&lt;/code&gt; values as its &lt;code&gt;:positions&lt;/code&gt;, as the board is empty and has 9 by 9 positions. The player with the black stones is the first to move, so the &lt;code&gt;:current&lt;/code&gt; key is set to &lt;code&gt;:black&lt;/code&gt; for any new state.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;State&lt;/code&gt; module exposes two functions. The first is &lt;code&gt;place/2&lt;/code&gt; which places a new stone on the board. If the new stone steals all the liberties of another stone, the captured stone is removed from the board automatically.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;legal?/2&lt;/code&gt; function checks if a move is legal by checking if another stone already occupies the position and making sure the stone wouldn&amp;#39;t be immediately captured.&lt;/p&gt;
&lt;p&gt;-&amp;gt; If you’d like to learn more about the implementation of the &lt;code&gt;State&lt;/code&gt; module that we’ll use, check out the &lt;a href=&quot;https://github.com/jeffkreeftmeijer/hayago/blob/starter/lib/hayago/state.ex&quot;&gt;module’s documentation&lt;/a&gt;, which explains how it handles placing stones on the board, capturing stones and validating possible moves.&lt;/p&gt;
&lt;h2&gt;The &lt;code&gt;GameLive&lt;/code&gt; Module&lt;/h2&gt;
&lt;p&gt;We’ll start by rendering the board. First, we add a live view to our application to handle rendering and updating the board. It’s called &lt;code&gt;GameLive&lt;/code&gt;, and it has &lt;code&gt;render/1&lt;/code&gt; and &lt;code&gt;mount/2&lt;/code&gt; callback functions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  use Phoenix.LiveView

  def render(assigns) do
    HayagoWeb.GameView.render(&amp;quot;index.html&amp;quot;, assigns)
  end

  def mount(_session, socket) do
    {:ok, assign(socket, state: %Hayago.State{})}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;mount/2&lt;/code&gt; callback sets up the assigns in the &lt;code&gt;socket&lt;/code&gt; to set the initial state for the view. We use it to create a new state, then add it to the socket assigns to make it available in the template.&lt;/p&gt;
&lt;p&gt;Next, we’ll add a template to render the board. We name it &lt;code&gt;index.html.leex&lt;/code&gt;, making it a &lt;em&gt;Live EEx&lt;/em&gt; template. Although similar to regular EEx templates, live templates track changes in order to send a minimal amount of data over the wire whenever the view updates.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/templates/game/index.html.leex
&amp;lt;div class=&amp;quot;board &amp;lt;%= @state.current %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;%= for _position &amp;lt;- @state.positions do %&amp;gt;
    &amp;lt;button&amp;gt;&amp;lt;/button&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;We loop over all positions in the &lt;code&gt;@state&lt;/code&gt; struct we assigned in the live view and an empty &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; elements for each. The buttons are in a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element, which the stylesheet automatically styles as a Go board. We’ll also add the current color as a class name to the board, to allow the stylesheet to show the stone you’re about to place when you hover over a position.&lt;/p&gt;
&lt;p&gt;Finally, we route any requests to &lt;code&gt;/&lt;/code&gt; to our &lt;code&gt;GameLive&lt;/code&gt; module in our router:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/router.ex
defmodule HayagoWeb.Router
  # ...

  scope &amp;quot;/&amp;quot;, HayagoWeb do
    pipe_through :browser

    live &amp;quot;/&amp;quot;, GameLive
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we start the Phoenix server and navigate to &lt;a href=&quot;https://localhost:4000&quot;&gt;https://localhost:4000&lt;/a&gt; in our browser, we&amp;#39;ll see the app render an empty Go board. While we can&amp;#39;t place stones just yet, hovering over the positions on the board shows us where a new stone would be placed.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/beeeaf56c296541dd6b7849a3e9ef6e60ee70cc3/814b9/videos/go_1.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/57a3671923248af647451a60c4d7d273f1fb9631/696c0/videos/go_1.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/07434561417df9605503e2b5e54d5f0b9090629d/e234c/videos/go_1.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;h2&gt;Making Moves&lt;/h2&gt;
&lt;p&gt;To place stones on the board, &lt;code&gt;State&lt;/code&gt; implements a &lt;code&gt;place/2&lt;/code&gt; function that takes a &lt;code&gt;State&lt;/code&gt; struct and an index. It replaces the position that corresponds to the index with the value in the &lt;code&gt;:current&lt;/code&gt; key, which is either &lt;code&gt;:black&lt;/code&gt; or &lt;code&gt;:white&lt;/code&gt;, depending on which player’s turn it is.&lt;/p&gt;
&lt;p&gt;In the template, we add &lt;code&gt;phx-click&lt;/code&gt; and &lt;code&gt;phx-value&lt;/code&gt; attributes to our buttons. These attributes tell LiveView to send an event to our &lt;code&gt;GameLive&lt;/code&gt; module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/templates/game/index.html.leex
&amp;lt;div class=&amp;quot;board&amp;quot;&amp;gt;
  &amp;lt;%= for {value, index} &amp;lt;- Enum.with_index(@state.positions) do %&amp;gt;
    &amp;lt;button phx-click=&amp;quot;place&amp;quot; phx-value=&amp;quot;&amp;lt;%= index %&amp;gt;&amp;quot; class=&amp;quot;&amp;lt;%= value %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our live view, we handle the event by matching on the attributes we set in the template. We use the passed index to call &lt;code&gt;State.place/2&lt;/code&gt;, which returns a new state with the stone placed on the board. We&amp;#39;ll return a &lt;code&gt;:noreply&lt;/code&gt;-tuple with the new state.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def handle_event(&amp;quot;place&amp;quot;, index, %{assigns: assigns} = socket) do
    new_state = State.place(assigns.state, String.to_integer(index))
    {:noreply, assign(socket, state: new_state)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By updating the state in the socket, LiveView knows to rerender the parts of the template that changed. The updated page is then compared to the rendered page to apply a minimal patch to the already-rendered page.&lt;/p&gt;
&lt;p&gt;Back in our browser, which automatically refreshed the page after we made our changes, our project is already starting to look like a proper Go game. We can place stones on the board and even surround an enemy stone to have it removed!&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/2af3a41589a7724377b9e0beb28699d83932b5d1/129ad/videos/go_2.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/8797c8ec48cac8c168bc7d6f6d464781ccd72855/72e1a/videos/go_2.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/2ab3f952aaab3df2099dc41312b23873a10e5f96/d8d43/videos/go_2.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;p&gt;Look at all the things we&amp;#39;re not doing! We didn&amp;#39;t have to write any code to send data to the browser, and we didn&amp;#39;t have to worry about updating the rendered page. LiveView took care of updating the page whenever the state changed.&lt;/p&gt;
&lt;p&gt;However, if we click the same position twice, an already placed stone is replaced by another. To prevent this from happening, we should disable the buttons that represent illegal moves.&lt;/p&gt;
&lt;h2&gt;Preventing Illegal Moves&lt;/h2&gt;
&lt;p&gt;To prevent illegal moves, we’ll render a disabled button for every position that either has a stone on it already or one where a newly placed stone has no liberties.&lt;/p&gt;
&lt;p&gt;To make that work, we’ll use &lt;code&gt;State.legal?/2&lt;/code&gt;, which takes the current state and an index, and returns a value indicating whether the current player can place a stone there or not.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;div class=&amp;quot;board &amp;lt;%= @state.current %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;%= for {value, index} &amp;lt;- Enum.with_index(@state.positions) do %&amp;gt;
    &amp;lt;%= if Hayago.State.legal?(@state, index) do %&amp;gt;
      &amp;lt;button phx-click=&amp;quot;place&amp;quot; phx-value=&amp;quot;&amp;lt;%= index %&amp;gt;&amp;quot; class=&amp;quot;&amp;lt;%= value %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;
    &amp;lt;% else %&amp;gt;
      &amp;lt;button class=&amp;quot;&amp;lt;%= value %&amp;gt;&amp;quot; disabled=&amp;quot;disabled&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because LiveView takes care of updating the page, we can add an if-statement to the template that checks if placing a stone on each position is a legal move. If it is, we render the same button as before. Otherwise, we render a disabled button.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/81879f95c186022f95de9892ef7d165c757c1e62/83878/videos/go_3.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/794d76252864fe790e8d9ab0e289628e5c6263ef/ceb97/videos/go_3.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/b9f67c2d81306bfe14802ce7595f5ee7ce05202d/98692/videos/go_3.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;p&gt;The stylesheet makes sure not to show hovers for disabled buttons, and changes the cursor to indidcate that a stone can be placed there.&lt;/p&gt;
&lt;h2&gt;Capturing Stones&lt;/h2&gt;
&lt;p&gt;When capturing a stone, the &lt;code&gt;place/2&lt;/code&gt; function increments a counter in the current state&amp;#39;s &lt;code&gt;:captures&lt;/code&gt; map, which holds a counter for both the black and the white stones.&lt;/p&gt;
&lt;p&gt;For each captured stone, we’ll show a stone above the board. Since the captures are already available in the &lt;code&gt;@state&lt;/code&gt; struct we receive from the live view, we’ll loop over each of the counters to render a &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; with the correct class name for the stylesheet to turn into a button.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;&amp;lt;div class=&amp;quot;captures&amp;quot;&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;%= for _ &amp;lt;- 1..@state.captures.black, @state.captures.black &amp;gt; 0 do %&amp;gt;
      &amp;lt;span class=&amp;quot;black&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;%= for _ &amp;lt;- 1..@state.captures.white, @state.captures.white &amp;gt; 0 do %&amp;gt;
      &amp;lt;span class=&amp;quot;white&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we’re using a range in our list comprehension, we’ll make sure to add a filter that ensures that the list isn’t empty when looping over it.&lt;/p&gt;
&lt;Video&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/3f30b105cde80815f39148dd581f0006e3a06417/cac8a/videos/go_4.mp4&quot;
    type=&quot;video/mp4&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/732683ddbdf1c9b5696aee6b85ebb2a7e984d90d/b4eca/videos/go_4.ogv&quot;
    type=&quot;video/ogg&quot;
  /&gt;
  &lt;source
    src=&quot;https://d33wubrfki0l68.cloudfront.net/92e67e78a8d389ed1f2d6916cad8fd2e9e7f0f8b/548b4/videos/go_4.webm&quot;
    type=&quot;video/webm&quot;
  /&gt;
&lt;/Video&gt;

&lt;p&gt;Now, we have a way to keep track of which stones were captured, as the stones are displayed above the board.&lt;/p&gt;
&lt;h2&gt;Scoring, History and the Ko Rule&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve made some strides implementing Go, and we’ve now learned how to set up a LiveView project. We&amp;#39;ve seen that carefully updating the state is enough to make build an interface without having to worry about updating the view. Instead, we focussed on rendering a static representation of the current state, and left the work of updating the page the player sees up to LiveView. Aside from setting up our live view module, the code we wrote to show the state of the board was all done by adding logic to the template, and we didn&amp;#39;t have to write any JavaScript ourselves.&lt;/p&gt;
&lt;p&gt;However, there are still some things we should do. The next time we meet, we’ll add history to our game to allow players to undo moves and we’ll implement the &lt;a href=&quot;https://senseis.xmp.net/?Ko&quot;&gt;ko rule&lt;/a&gt; to prevent repeating moves. See you then!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Doing Background Work Using a Native Elixir Approach</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/05/14/elixir-alchemy-background-processing.html"/>
    <id>https://blog.appsignal.com/2019/05/14/elixir-alchemy-background-processing.html</id>
    <published>2019-05-14T00:00:00+00:00</published>
    <updated>2019-05-14T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this article, we&#039;ll look at the different solutions Elixir has for performing background work and when you would use each one.</summary>
    <content type="html">&lt;p&gt;If you&amp;#39;ve used Ruby before, &lt;em&gt;background job queues&lt;/em&gt; are a tool you might reflexively reach for when building applications in Elixir. While such solutions exist, you may find that they aren&amp;#39;t used that much in Elixir, which might leave you wondering why. I mean, don&amp;#39;t Elixir applications perform asynchronous jobs? Yes! But it&amp;#39;s thought about a bit differently.&lt;/p&gt;
&lt;p&gt;Today we&amp;#39;ll look at the different solutions Elixir has for performing background work, and when you would use which. Along the way, we&amp;#39;ll learn how Elixir&amp;#39;s native constructs make background work a beautiful matter of spawning a process.&lt;/p&gt;
&lt;h2&gt;Some Background: Background Job Queues&lt;/h2&gt;
&lt;p&gt;Almost all production Rails applications use a background job framework such as &lt;a href=&quot;https://sidekiq.org/&quot;&gt;Sidekiq&lt;/a&gt;. This is used to do a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defer expensive work so that users aren&amp;#39;t kept waiting, e.g. when setting up an account with data fetched from an external source&lt;/li&gt;
&lt;li&gt;Carry out ongoing background work that wasn&amp;#39;t initiated by a user, e.g. fetching the current value of a cryptocurrency&lt;/li&gt;
&lt;li&gt;Speed up response times by moving nonessential work (e.g. sending a welcome email) out of the user request cycle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we were to do this in Elixir, how would we handle it in a way that made use of Elixir&amp;#39;s strengths?&lt;/p&gt;
&lt;p&gt;Elixir has several tools for performing background work. The main ones are: &lt;em&gt;Supervisors&lt;/em&gt;, &lt;em&gt;GenServers&lt;/em&gt;, and &lt;em&gt;Tasks&lt;/em&gt;. Whichever one you chose to use depends on your application and use case. Let&amp;#39;s dive into when you would use each one!&lt;/p&gt;
&lt;h2&gt;Deferring Work&lt;/h2&gt;
&lt;p&gt;In the first example, let&amp;#39;s say we have a system that connects to two external data sources to complete a user&amp;#39;s account setup: we use a user-supplied address to find the order fulfillment center closest to their location, and then we send user-supplied name and birthday to a separate CRM. We then store &lt;code&gt;fulfillment_center_id&lt;/code&gt; and &lt;code&gt;crm_id&lt;/code&gt; keys on the user in our main database so that we can fetch those external records at some later time.&lt;/p&gt;
&lt;p&gt;The key aspects of this operation are that 1) the two pieces of work can be done independently of each other and 2) we want the work to retry in case it fails. We also aren&amp;#39;t concerned about the return values for these tasks—they write their side effects to the database outside the initial thread of operations. For this, we would use &lt;em&gt;supervised Tasks&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule YourApp.Application do
  use Application

  def start(_type, _args) do
    import Supervisor.Spec

    children = [
      {Task.Supervisor, name: YourApp.AccountSetupSupervisor}
    ]

    opts = [strategy: :one_for_one, name: YourApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We define a &lt;code&gt;Task.Supervisor&lt;/code&gt; that starts when our application launches. Here, we name it &lt;code&gt;YourApp.AccountSetupSupervisor&lt;/code&gt;, which gives it a nice semantic meaning for our use case. Your system can have many &lt;code&gt;Task.Supervisors&lt;/code&gt; for managing different types of tasks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule YourApp.AccountSetupSupervisor do
  def set_up_user_account(user) do
    opts = [restart: :transient]

    Task.Supervisor.start_child(__MODULE__, YourApp.CRM, :create_user, [user], opts)
    Task.Supervisor.start_child(__MODULE__, YourApp.Fulfillment, :set_nearest_location, [user], opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Here&amp;#39;s our task supervisor with the key function &lt;code&gt;set_up_user_account/1&lt;/code&gt;. It&amp;#39;s called by either a controller or account context to complete the account setup once the basic user data has been saved to the database. The function spawns two tasks, with each task executing the specified function for connecting to our CRM and our Fulfillment Service.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;restart: :transient&lt;/code&gt; option tells the supervisor to restart the task if it exits abnormally, for example, when a connection fails and the process crashes. By default, the supervisor will try restarting the process up to 3 times in 5 seconds before giving up. If the operation is successful, the process exits normally and everything goes on as usual.&lt;/p&gt;
&lt;p&gt;This code expects us to have a module &lt;code&gt;YourApp.CRM&lt;/code&gt; with a function &lt;code&gt;create_user/1&lt;/code&gt; and a module &lt;code&gt;YourApp.Fulfillment&lt;/code&gt; with a function &lt;code&gt;set_nearest_location/1&lt;/code&gt;. Here&amp;#39;s what one of those modules might look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule YourApp.CRM do

  def create_user(user) do
    crm_data =
      user
      |&amp;gt; fetch_crm_data()
      |&amp;gt; parse()

    user
    |&amp;gt; YourApp.User.crm_changeset(crm_data)
    |&amp;gt; YourApp.Repo.update!()
  end

  defp fetch_crm_data(user) do
    # your code here
  end

  defp parse(data) do
    # you will probably want to parse results for use in a changeset
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;YourApp.Fulfillment&lt;/code&gt; would look similar. Structuring our code this way makes for clean interfaces, single responsibilities, and reusable components.&lt;/p&gt;
&lt;p&gt;Now the user won&amp;#39;t experience any lags while the system is hard at work. The controller immediately returns to the user, who can see a helpful screen while the system continues doing its thing in the background. Sweet as stroopwafels!&lt;/p&gt;
&lt;h2&gt;Ongoing Background Work&lt;/h2&gt;
&lt;p&gt;Okay, what about &lt;em&gt;ongoing background work&lt;/em&gt; which happens regularly and is not initiated by a user? I would use an ordinary &lt;em&gt;GenServer&lt;/em&gt; for this. Two things that make GenServers great are that you don&amp;#39;t have to serialize their arguments like you do with Sidekiq, and thanks to the BEAM&amp;#39;s fair scheduling, the resource-intensive processes will not be a huge drain on your user-facing responsiveness. Plus, you can easily monitor what your Genserver is doing with the help of the &lt;code&gt;observer&lt;/code&gt; by dropping some useful statistics into its &lt;code&gt;state&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s dive into the cryptocurrency account value example. Let&amp;#39;s say our frontend is wired up to update the DOM in real-time via Phoenix LiveView. We need to ping our node every second for the latest data, then use that data to refresh what the user sees. For such recurring tasks, I use a technique where I start up a GenServer during application startup. The GenServer requests the BEAM to send it a &lt;code&gt;work&lt;/code&gt; message after 1000ms and then goes to sleep. After the interval elapses, the BEAM sends the message to the GenServer, which wakes up, does the work, schedules another message to be sent in 1000ms, and goes back to sleep.&lt;/p&gt;
&lt;p&gt;The key piece is that sleeping processes don&amp;#39;t affect system performance, so you can have many of these schedulers all sleeping at the same time, perhaps one for each user.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CryptoApp.AccountSync do
  use GenServer

  @interval 1_000

  def start_link do
    GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
  end

  def init(:ok) do
    Process.send_after(self(), :work, @interval)
    {:ok, %{last_run_at: nil}}
  end

  def handle_info(:work, state) do
    fetch_account_balance()
    Process.send_after(self(), :work, @interval)

    # By storing last_run_at in state we get basic monitoring via process inspection.
    # It&amp;#39;s just for convenience - don&amp;#39;t use this technique for sophisticated instrumentation of your processes.
    {:noreply, %{last_run_at: :calendar.local_time()}}
  end

  defp fetch_account_balance do
    # your code here
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, our GenServer handles both the scheduling and the work itself, which can produce some drift in our timing. This may be fine for your use case, but, if the work must happen on timed intervals, have the scheduling GenServer create a &lt;em&gt;new&lt;/em&gt; process for doing the work, leaving it only responsible for setting the timer.&lt;/p&gt;
&lt;p&gt;Note that if you spin up a GenServer for each user, you can end up hammering the external resource with requests for the latest data. Remember, GenServers are all working concurrently! Scheduling and concurrency are easy in Elixir—perhaps too easy. As the programmer, you must still understand how your system works and whether concurrency is right for you.&lt;/p&gt;
&lt;h2&gt;Moving Nonessential Work&lt;/h2&gt;
&lt;p&gt;Now onto the third scenario where we want to speed up response times to the user by pulling out nonessential work. The key word is &amp;quot;nonessential&amp;quot; which includes operations that are one-offs or fire-and-forget. If a welcome email doesn&amp;#39;t get sent to the user or a single data point is dropped, that&amp;#39;s okay. You can simply wrap your code in a &lt;code&gt;Task.start&lt;/code&gt; block and that&amp;#39;s it!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule App.UserService do

  def create_user(params) do
    %App.User{}
    |&amp;gt; App.User.changeset(params)
    |&amp;gt; App.Repo.insert()
    |&amp;gt; case do
      {:ok, user} -&amp;gt;
        Task.start(fn -&amp;gt; send_email_to_user(user) end) # 🎉
        {:ok, user}

      {:error, changeset} -&amp;gt;
        {:error, changeset}
    end
  end

  defp send_email_to_user(user) do
    # send the email
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The disadvantage of this approach is that it doesn&amp;#39;t give you the option to retry in case of failure. For critical work, start a supervisor and have it spawn a task that can be restarted.&lt;/p&gt;
&lt;h2&gt;Other Considerations and RabbitMQ&lt;/h2&gt;
&lt;p&gt;Don&amp;#39;t take this to mean that you should never use a background job framework. There are situations where it makes sense to use one. For example, if your system reboots in the middle of a job, the work might be lost. In such cases, you need to have in place an independent system that survives application restarts. A message broker like &lt;a href=&quot;https://www.rabbitmq.com/&quot;&gt;RabbitMQ&lt;/a&gt; would be the way to go. But that&amp;#39;s a topic for another day. We could (and might) write a whole blog about it.&lt;/p&gt;
&lt;p&gt;Also, be thoughtful when it comes to retrying jobs. Does it really need to be retried? Often, when failures rack up in our Sidekiq dashboard, we just clear them out. Important retries are usually done manually, or at least under close supervision by an engineer, instead of being blindly requeued.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;A background job system has many moving pieces and thus, points of failure. They may be worth it, but we should not build one into our Elixir application until we have thoughtfully examined our use cases. Erlang&amp;#39;s process model gives us a diverse toolkit for solving these sorts of problems and we should not make the mistake of writing Elixir code as though it&amp;#39;s Ruby. It&amp;#39;s not. The more we learn about processes, the better and more idiomatic our architectural decisions will be. We hope this was a fun step in that learning path.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Routing in Phoenix Umbrella Apps</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/04/16/elixir-alchemy-routing-phoenix-umbrella-apps.html"/>
    <id>https://blog.appsignal.com/2019/04/16/elixir-alchemy-routing-phoenix-umbrella-apps.html</id>
    <published>2019-04-16T00:00:00+00:00</published>
    <updated>2019-04-16T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Today, we’re diving into Phoenix umbrella applications to build a router that can route requests from multiple subdomains to different apps in our umbrella.</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://elixirschool.com/en/lessons/advanced/umbrella-projects/&quot;&gt;Umbrella apps&lt;/a&gt; are an awesome way to structure Elixir projects.&lt;/p&gt;
&lt;p&gt;Behind the curtains, they are a very thin layer that just compiles everything to a single package. Instead of building a single large monolith, you can structure your code with multiple isolated contexts. They all get compiled and run under the same BEAM instance, so they still have access to each other. Meanwhile the conceptual separation ensures you have separate OTP apps for each of your umbrella children. And it allows you to work on each of them with a certain degree of isolation.&lt;/p&gt;
&lt;p&gt;Think of this as a poor man’s microservices solution. You don’t need to add a messaging queue or send HTTP requests between each service since they’re all actually running under the same process, but you still get some of the benefits.&lt;/p&gt;
&lt;p&gt;If you want to know more about umbrella applications, I suggest &lt;a href=&quot;https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html#umbrella-projects&quot;&gt;the official guide&lt;/a&gt; as a starter, as it clearly outlines the advantages and caveats of umbrella apps.&lt;/p&gt;
&lt;p&gt;Now let&amp;#39;s look at a real life example where I&amp;#39;ve implemented an umbrella app.&lt;/p&gt;
&lt;h2&gt;A Real Example&lt;/h2&gt;
&lt;p&gt;Let’s say I’m building a website for &lt;a href=&quot;https://en.wikipedia.org/wiki/Magic:_The_Gathering&quot;&gt;Magic: The Gathering (MTG)&lt;/a&gt; cards. Which… well, &lt;a href=&quot;https://github.com/naps62/mse&quot;&gt;I am&lt;/a&gt;. The idea is to create an interface where users can browse and search a database of cards. There’s also an admin panel where some administrative tasks can be performed.&lt;/p&gt;
&lt;p&gt;Clearly, each of these frontend interfaces has different requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The main frontend is public while the admin side only has private access.&lt;/li&gt;
&lt;li&gt;The admin panel may even have its own UI requirements. In this case, I’m using &lt;a href=&quot;https://github.com/smpallen99/ex_admin&quot;&gt;ex_admin&lt;/a&gt; for convenience. This means, even UI assets are not shared.&lt;/li&gt;
&lt;li&gt;They mostly have completely different back-end logic as well. Only a small subset of the queries and operations can be shared between the two.&lt;/li&gt;
&lt;li&gt;I may also want to access both of them through different URLs (e.g. use an &lt;code&gt;admin&lt;/code&gt; subdomain for the Admin frontend).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The multiple differences between the two make it clear that it would be better for these to be two separate phoenix apps—each with its own setup.&lt;/p&gt;
&lt;p&gt;Something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;apps/
  client/
  admin/
  shared/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Looks Easy Enough. What’s the Issue?&lt;/h2&gt;
&lt;p&gt;The problem comes when you try to figure out how to actually implement this. How do you route requests from the &lt;code&gt;admin&lt;/code&gt; subdomain to another Phoenix app while routing other requests to the main Phoenix app?&lt;/p&gt;
&lt;p&gt;One solution would be to run each of those apps on a different port. But then, you&amp;#39;ll either be left accessing &lt;code&gt;admin.mydomain.com:4001&lt;/code&gt;, or you’ll need some other middle layer to abstract away that port distinction from your browser. While this may be fine for an admin page that only you will access, it doesn’t work as well for a general solution.&lt;/p&gt;
&lt;p&gt;The old school solution is to put a reverse proxy between your clients and your server. nginx does this job pretty well. But in reality, you know all this is a single Elixir application. It seems weird to need a third party server to be able to route requests to different parts of it.&lt;/p&gt;
&lt;p&gt;It also doesn’t solve the problem of local development, unless you want to run nginx locally as well, which is less than ideal.&lt;/p&gt;
&lt;p&gt;We’re Elixir developers after all, and we’re pretty smart. So let’s do this the Elixir way:&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Introducing a Proxy App&lt;/h2&gt;
&lt;p&gt;The solution I came up with (i.e. read suggestions from similar use cases on Stack Overflow) was to create an additional umbrella child, which will be the main point of contact to the outside world.&lt;/p&gt;
&lt;p&gt;This app, which we’ll call &lt;code&gt;proxy&lt;/code&gt;, will receive all incoming HTTP requests and forward them to the appropriate Phoenix app, based on a few simples rules. In our simple use case, requests to &lt;code&gt;admin.mydomain.com&lt;/code&gt; will be forwarded to the &lt;code&gt;admin&lt;/code&gt; app, and all others will be forwarded to the &lt;code&gt;client&lt;/code&gt; app.&lt;/p&gt;
&lt;p&gt;This is a very simple phoenix app, which you can generate with &lt;code&gt;mix phx.new&lt;/code&gt; like all the others. Dependencies will be kept to a minimum here. We only have phoenix &amp;amp; cowboy as external dependencies (to set up our web server), as well as the client and admin apps to which we’ll be forwarding requests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;def deps do
  [
    {:client, in_umbrella: true},
    {:admin, in_umbrella: true},
    {:phoenix, &amp;quot;~&amp;gt; 1.3.2&amp;quot;},
    {:cowboy, &amp;quot;~&amp;gt; 1.0&amp;quot;}
  ]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since this app will be the actual web server, we should disable the server setting in the other two:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;# apps/client/config/config.exs
config :client, Client.Web.Endpoint, server: false

# apps/admin/config/config.exs
config :admin, Admin.Web.Endpoint, server: false

# apps/proxy/config/config.exs
config :proxy, Proxy.Endpoint, server: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures that only the proxy app will be listening to a port. This is not mandatory but it saves you the trouble of having to define different ports for each one (remember: only one listener per port is allowed) and ensures all requests actually go through the proxy app—which is indeed the expected behavior.&lt;/p&gt;
&lt;p&gt;Leaving &lt;code&gt;server: true&lt;/code&gt; might be useful in development or testing mode, depending on how you want to set up your environment.&lt;/p&gt;
&lt;h2&gt;Setting up the Endpoint&lt;/h2&gt;
&lt;p&gt;The entry point of a Phoenix app is the &lt;code&gt;Endpoint&lt;/code&gt; module. In this case, we’ve set this to &lt;code&gt;Proxy.Endpoint&lt;/code&gt;. Since this app really has no other responsibility, there’s no need to nest it under the &lt;code&gt;Web&lt;/code&gt; module, as is common practice in Phoenix.&lt;/p&gt;
&lt;p&gt;However, we can strip down most things from the Endpoint module created for us by the Phoenix generator and end up with a very simple module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;defmodule Proxy.Endpoint do
  use Phoenix.Endpoint, otp_app: :proxy

  @base_host_regex ~r|\.?mydomain.*$|
  @subdomains %{
    &amp;quot;admin&amp;quot; =&amp;gt; Admin.Web.Endpoint,
    &amp;quot;client&amp;quot; =&amp;gt; Client.Web.Endpoint
  }
  @default_host Client.Web.Endpoint

  def init(opts), do: opts

  def call(conn, _) do
    with subdomain &amp;lt;- String.replace(host, @base_host_regex, &amp;quot;&amp;quot;),
         endpoint &amp;lt;- Map.get(@subdomains, subdomain, @default_host) do
      endpoint.call(conn, endpoint.init())
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s go over this one step at a time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;@base_host_regex ~r|\.?mydomain.*$|
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is used to extract the subdomain part of the host URL of every request. So for &lt;code&gt;admin.mydomain.com&lt;/code&gt; we want to get the string &lt;code&gt;admin&lt;/code&gt; and for &lt;code&gt;mydomain.com&lt;/code&gt; we will end up with an empty string (meaning, we’ll forward this to the default app. More on that later).&lt;/p&gt;
&lt;p&gt;Notice that this doesn’t exactly match the &lt;code&gt;.com&lt;/code&gt; part. This is a convenience change I made for local development. Matching on &lt;code&gt;mydomain.*&lt;/code&gt; allows me to use &lt;code&gt;admin.mydomain.lvh.me&lt;/code&gt; when working on my local machine, and still have this whole logic working without making development-specific changes.&lt;/p&gt;
&lt;p&gt;If you don’t know what &lt;code&gt;lvh.me&lt;/code&gt; is, &lt;a href=&quot;https://nickjanetakis.com/blog/ngrok-lvhme-nipio-a-trilogy-for-local-development-and-testing#lvh-me&quot;&gt;this article&lt;/a&gt; might be helpful (TL;DR: It’s a development service that resolves its name to &lt;code&gt;localhost&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;With the above regex in mind, the next part should be easy to understand:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;@subdomains %{
    &amp;quot;admin&amp;quot; =&amp;gt; Admin.Web.Endpoint,
    &amp;quot;client&amp;quot; =&amp;gt; Client.Web.Endpoint
}
@default_host Client.Web.Endpoint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For every subdomain, we want to match a particular Phoenix endpoint belonging to the app that we want to forward the request to. &lt;code&gt;@default_host&lt;/code&gt; is what we’ll use if the subdomain is missing (the empty string scenario we talked above).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ruby&quot;&gt;def call(conn, _) do
    with subdomain &amp;lt;- String.replace(host, @base_host_regex, &amp;quot;&amp;quot;),
         endpoint &amp;lt;- Map.get(@subdomains, subdomain, @default_host) do
      endpoint.call(conn, endpoint.init())
    end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When this endpoint—which is actually not much more than an &lt;a href=&quot;https://hexdocs.pm/plug/readme.html&quot;&gt;Elixir Plug&lt;/a&gt;—is called, we just grab the subdomain from the request host, then find the matching endpoint from our mapping (defaulting to &lt;code&gt;@default_host&lt;/code&gt;), and call &lt;code&gt;endpoint.call/2&lt;/code&gt; on it. This is essentially delegating the call down to the appropriate app.&lt;/p&gt;
&lt;p&gt;Now &lt;code&gt;client&lt;/code&gt; and &lt;code&gt;admin&lt;/code&gt; both have to only worry about their corresponding requests and authentication. All logic related to the multiple subdomains &amp;amp; clients we may need is abstracted away in this app.&lt;/p&gt;
&lt;p&gt;Want a new client in the same umbrella? Add it here! Want the same endpoint to respond to additional subdomains? Add it here!&lt;/p&gt;
&lt;h2&gt;Taking the routing even further&lt;/h2&gt;
&lt;p&gt;By adding a smart router to our umbrella application, we’re now able to serve requests to different subdomains to different apps in our umbrella application. I first implemented this pattern on &lt;a href=&quot;https://github.com/naps62/mse/tree/master/apps/proxy&quot;&gt;a pet project of mine&lt;/a&gt;, but have since used and improved it on a few production projects as well.&lt;/p&gt;
&lt;p&gt;We could take this much further. For example, if you’re migrating an existing service from Ruby to Elixir. You can have this proxy application route all requests made to the Ruby version of your service redirected back to the Ruby application, ensuring backward-compatibility. Or you may want the opposite scenario, where you’re creating a new API service and want to forward matching requests to a different client or even to a different web server altogether.&lt;/p&gt;
&lt;p&gt;We can also take the routing complexity to another level. Routing was done here based solely on the subdomain of the request. But depending on your needs, you can create more complex routing rules using HTTP headers or query parameters. All of this can be done while keeping your actual web services completely oblivious to it.&lt;/p&gt;
&lt;p&gt;We had a blast 💥thinking about all the possibilities of Umbrellas and Routing. We hope it set your mind on 🔥fire as well. If you want to get a regular dose of ⚗️Elixir Alchemy, &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe&lt;/a&gt; to get the next episode of Alchemy delivered straight to your inbox.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Iteration, Recursion, and Tail-call Optimization in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/03/19/elixir-alchemy-recursion.html"/>
    <id>https://blog.appsignal.com/2019/03/19/elixir-alchemy-recursion.html</id>
    <published>2019-03-19T00:00:00+00:00</published>
    <updated>2019-03-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">It’s time for another Elixir Alchemy! This week, we’ll dive into recursion in Elixir to find the fastest looping method. (Spoiler: it depends). 🎢</summary>
    <content type="html">&lt;p&gt;Elixir uses recursion for looping over data structures like lists. Although most of it&amp;#39;s hidden away through higher-level abstractions on the &lt;code&gt;Enum&lt;/code&gt; module, in some cases writing a recursive function yourself can be more performant. In this episode of Elixir Alchemy, we’ll try to find some of these cases.&lt;/p&gt;
&lt;p&gt;Along the way, we’ll learn about body-recursive and tail-recursive functions. Although the latter is often touted as being faster, we’ll also look at cases where that’s not necessarily true. Let’s dive right in!&lt;/p&gt;
&lt;h2&gt;Enumeration&lt;/h2&gt;
&lt;p&gt;Elixir provides functions on the &lt;code&gt;Enum&lt;/code&gt; module to enumerate over collections.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def sum_numbers1(list) do
  list
  |&amp;gt; Enum.filter(&amp;amp;is_number/1)
  |&amp;gt; Enum.reduce(0, fn n, sum -&amp;gt; n + sum end)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example takes a list and returns the sum of all numbers in that list. Because there might be non-numeric items in the input list, it uses &lt;code&gt;Enum.filter/2&lt;/code&gt; to select only the items that &lt;code&gt;is_number/1&lt;/code&gt; returns true on. After that, the remaining values are added together through &lt;code&gt;Enum.reduce/3&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;sum_numbers1([1, 2, &amp;quot;three&amp;quot;, 4, %{}]) # =&amp;gt; 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this solution works, it iterates over the whole list twice to get to the result. To make this more performant, we might instead choose to write a recursive function that can do this in one go.&lt;/p&gt;
&lt;h2&gt;Recursion&lt;/h2&gt;
&lt;p&gt;A recursive function can do both tasks (removing the non-numeric items and adding the rest together) in one run. It will call itself for every item in the list, and use pattern matching to decide what to do with each item.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# 1
def sum_numbers2([head | tail]) when is_number(head) do
  sum_numbers2(tail) + head
end

# 2
def sum_numbers2([_head | tail]) do
  sum_numbers2(tail)
end

# 3
def sum_numbers2([]) do
  0
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of using the functions provided by the &lt;code&gt;Enum&lt;/code&gt; module, this solution calls itself until the list is empty. It does so using three function heads:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When the first item in the list (the &lt;em&gt;head&lt;/em&gt;) is a number, we&amp;#39;ll call &lt;code&gt;sum_numbers2/1&lt;/code&gt; with the rest of list (anything but the head, called the &lt;em&gt;tail&lt;/em&gt;). This call returns a number we&amp;#39;ll add our current head to.&lt;/li&gt;
&lt;li&gt;When the head is &lt;em&gt;not&lt;/em&gt; a number, we&amp;#39;ll drop it by calling the &lt;code&gt;sum_numbers2/1&lt;/code&gt; function with just the tail.&lt;/li&gt;
&lt;li&gt;When the list is empty, we&amp;#39;ll return 0.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;sum_numbers2([1, 2, &amp;quot;three&amp;quot;, 4, %{}]) # =&amp;gt; 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When calling this function with &lt;code&gt;[1, 2, &amp;quot;three&amp;quot;, 4, %{}]&lt;/code&gt;, the &lt;code&gt;sum_numbers2/1&lt;/code&gt; function is called repeatedly in the following order to get to the result:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sum_numbers2([1, 2, &amp;quot;three&amp;quot;, 4, %{}])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sum_numbers2([2, &amp;quot;three&amp;quot;, 4, %{}]) + 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sum_numbers2([&amp;quot;three&amp;quot;, 4, %{}]) + 1 + 2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sum_numbers2([4, %{}]) + 1 + 2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sum_numbers2([%{}]) + 1 + 2 + 4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sum_numbers2([]) + 1 + 2 + 4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0 + 1 + 2 + 4&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This list shows the how the function is simplified until we get to a result, which shows the function being called six times. Once for each item, plus once more for the empty list at the end.&lt;/p&gt;
&lt;p&gt;Because the function calls itself for each iteration, each item in the list causes a &lt;a href=&quot;https://en.wikipedia.org/wiki/Call_stack#STACK-FRAME&quot;&gt;stack frame&lt;/a&gt; to be added to the call stack. That’s because each item warrants a call to a function, which needs to be executed to claim its result. Adding a stack frame to the call stack requires some memory to be allocated, and can cause some overhead.&lt;/p&gt;
&lt;h2&gt;Tail recursion and tail-call optimization&lt;/h2&gt;
&lt;p&gt;To keep the memory footprint to a minimum, some languages—like Erlang and thus Elixir—implement tail-call optimization. With a small rewrite of our code, we can prevent the stack frame being added and that memory allocated.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# 1
def sum_numbers3(list) do
  do_sum_numbers3(list, 0)
end

# 2
defp do_sum_numbers3([head | tail], sum) when is_number(head) do
  do_sum_numbers3(tail, sum + head)
end

# 3
defp do_sum_numbers3([_head | tail], sum) do
  do_sum_numbers3(tail, sum)
end

# 4
defp do_sum_numbers3([], sum) do
  sum
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;This example is yet another implementation of the function from before. However, this example is tail-recursive, meaning it doesn’t need to await a call to itself before continuing. It does so by keeping an accumulator (&lt;code&gt;sum&lt;/code&gt;) that keeps the current value instead of stacking function calls.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;sum_numbers3/1&lt;/code&gt; function is the public function, which calls the private &lt;code&gt;do_sum_numbers3/2&lt;/code&gt; function with the passed list and an accumulator of &lt;code&gt;0&lt;/code&gt; to start with.&lt;/li&gt;
&lt;li&gt;Much like the previous example, &lt;code&gt;do_sum_numbers3/2&lt;/code&gt;&amp;#39;s first function head matches lists with a numeric &lt;em&gt;head&lt;/em&gt;. It calls itself with the list&amp;#39;s &lt;em&gt;tail&lt;/em&gt;, and the &lt;em&gt;head&lt;/em&gt; added to the accumulator.&lt;/li&gt;
&lt;li&gt;When the &lt;em&gt;head&lt;/em&gt; is not a number, the third function head drops it by calling itself with the &lt;em&gt;tail&lt;/em&gt; and the current accumulator, without changing anything.&lt;/li&gt;
&lt;li&gt;Finally, the exit clause returns the accumulator.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By calling itself at the end of the function and passing the accumulator with all calculated values, the Erlang VM can execute a trick called tail-call optimization, which allows it to circumvent adding new stack frames. Instead, it uses the current frame by jumping back up to the beginning of the function.&lt;/p&gt;
&lt;p&gt;Tail call optimization allows functions calling themselves without running into stack problems.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def sleep, do: sleep
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example implements a function that continually calls itself. Without tail-call optimization, this function would produce a stack error.&lt;/p&gt;
&lt;h2&gt;Which is faster?&lt;/h2&gt;
&lt;p&gt;We&amp;#39;ve written three implementations of the same function. The first used &lt;code&gt;Enum.filter/2&lt;/code&gt; and &lt;code&gt;Enum.reduce/3&lt;/code&gt; to filter and sum the list, and iterated over the list twice. To fix that, we used a recursive function that did it in one go, which we further improved using tail-call optimization.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;letters = Enum.map(?a..?z, fn x -&amp;gt; &amp;lt;&amp;lt;x::utf8&amp;gt;&amp;gt; end)
numbers = Enum.to_list(0..10_000)
list = Enum.shuffle(letters ++ numbers)

Benchee.run(
  %{
    &amp;quot;Enum.filter/2 and Enum.reduce/3&amp;quot; =&amp;gt; fn -&amp;gt; Recursion.sum_numbers1(list) end,
    &amp;quot;Body-recursive&amp;quot; =&amp;gt; fn -&amp;gt; Recursion.sum_numbers2(list) end,
    &amp;quot;Tail-recursive&amp;quot; =&amp;gt; fn -&amp;gt; Recursion.sum_numbers3(list) end
  },
  time: 10,
  memory_time: 2
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To benchmark our solutions, we&amp;#39;ll use &lt;a href=&quot;https://github.com/PragTob/benchee&quot;&gt;Benchee&lt;/a&gt;. We&amp;#39;ll prepare a shuffled list of strings and numbers for each function to sum for ten seconds.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Name                                      ips        average  deviation         median         99th %
Tail-recursive                       107.35 K        9.32 μs    ±21.39%           9 μs          14 μs
Body-recursive                        55.65 K       17.97 μs   ±662.77%          14 μs          34 μs
Enum.filter/2 and Enum.reduce/3       20.86 K       47.94 μs    ±51.46%          46 μs          85 μs

Comparison:
Tail-recursive                       107.35 K
Body-recursive                        55.65 K - 1.93x slower
Enum.filter/2 and Enum.reduce/3       20.86 K - 5.15x slower

Memory usage statistics:

Name                               Memory usage
Tail-recursive                              0 B
Body-recursive                              0 B
Enum.filter/2 and Enum.reduce/3         16064 B
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this test on this machine, we see that the body-recursive version is almost three times as fast as the original implementation that used &lt;code&gt;Enum.filter/2&lt;/code&gt; and &lt;code&gt;Enum.reduce/3&lt;/code&gt;. The tail-recursive version was almost twice as fast ad the body-recursive one.&lt;/p&gt;
&lt;h2&gt;Is tail-call recursion always faster?&lt;/h2&gt;
&lt;p&gt;While the results of that benchmark look quite convincing, tail-recursion isn&amp;#39;t always faster than body recursion. In fact, that&amp;#39;s one of the &lt;a href=&quot;http://erlang.org/doc/efficiency_guide/myths.html&quot;&gt;7 myths of Erlang performance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While tail-recursive calls are usually faster for list reductions—like the example we’ve seen before—body-recursive functions can be faster in some situations. That&amp;#39;s often true when mapping over a list, where the function takes a list and returns a list without reducing it to a single value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def double_numbers1(list) do
  list
  |&amp;gt; Enum.filter(&amp;amp;is_number/1)
  |&amp;gt; Enum.map(fn n -&amp;gt; n * 2 end)
end

def double_numbers2([]) do
  []
end

def double_numbers2([head | tail]) when is_number(head) do
  [head * 2 | double_numbers2(tail)]
end

def double_numbers2([_head | tail]) do
  double_numbers2(tail)
end

def double_numbers3(list) do
  list
  |&amp;gt; do_double_numbers3([])
  |&amp;gt; Enum.reverse()
end

defp do_double_numbers3([], acc) do
  acc
end

defp do_double_numbers3([head | tail], acc) when is_number(head) do
  do_double_numbers3(tail, [head * 2 | acc])
end

defp do_double_numbers3([_head | tail], acc) do
  do_double_numbers3(tail, acc)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example is a lot like the example we&amp;#39;ve seen before, but instead of adding all numbers together and reducing them to a single number, the &lt;code&gt;double_numbers/1&lt;/code&gt; function doubles all numbers and returns them in a list.&lt;/p&gt;
&lt;p&gt;Like before, we have three implementations. The first uses &lt;code&gt;Enum.filter/2&lt;/code&gt; and &lt;code&gt;Enum.map/2&lt;/code&gt; to iterate over the list twice, the second is body-recursive and the last is tail-recursive. Before returning, the tail-recursive function needs to reverse the list, because the values get prepended to the accumulator.&lt;/p&gt;
&lt;p&gt;-&amp;gt; Check out the &lt;a href=&quot;https://github.com/jeffkreeftmeijer/elixir-recursion-example&quot;&gt;example project&lt;/a&gt; for a comparison of more possible implementations, like list comprehensions and a tail-recursive version that doesn&amp;#39;t reverse the list.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Name                                   ips        average  deviation         median         99th %
body-recursive                     36.86 K       27.13 μs    ±39.82%          26 μs          47 μs
tail-recursive                     27.46 K       36.42 μs  ±1176.74%          27 μs          80 μs
Enum.filter/2 and Enum.map/2       12.62 K       79.25 μs   ±194.81%          62 μs         186 μs

Comparison:
body-recursive                     36.86 K
tail-recursive                     27.46 K - 1.34x slower
Enum.filter/2 and Enum.map/2       12.62 K - 2.92x slower

Memory usage statistics:

Name                            Memory usage
body-recursive                      15.64 KB
tail-recursive                      20.09 KB - 1.28x memory usage
Enum.filter/2 and Enum.map/2        31.33 KB - 2.00x memory usage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When running a benchmark for each of these implementations, we can see that the body-recursive version is fastest in this case. Having to reverse the list in the tail-recursive version negates the improved performance tail-call optimization adds in this specific case.&lt;/p&gt;
&lt;h2&gt;As always, it depends&lt;/h2&gt;
&lt;p&gt;This concludes our look into recursion in Elixir. As a rule of thumb; tail-recursive functions are faster if they don&amp;#39;t need to reverse the result before returning it. That&amp;#39;s because that requires another iteration over the whole list. Tail-recursive functions are usually faster at reducing lists, like our first example.&lt;/p&gt;
&lt;p&gt;Which is the best approach depends on the situation. For mission-critical loops, writing a benchmark to measure which solution is faster is usually your best bet, as it&amp;#39;s not immediately obvious which will perform better.&lt;/p&gt;
&lt;p&gt;To learn more about recursion, also be sure to read &lt;a href=&quot;/2019/03/19/elixir-alchemy-recursion.html&quot;&gt;this overview&lt;/a&gt; of the available methods, and when to use which. If you liked this article, don&amp;#39;t forget to &lt;a href=&quot;/elixir-alchemy&quot;&gt;subscribe to the mailing list&lt;/a&gt; if you&amp;#39;d like to read more Elixir Alchemy!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Pouring Protocols in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/02/19/elixir-alchemy-pouring-protocols.html"/>
    <id>https://blog.appsignal.com/2019/02/19/elixir-alchemy-pouring-protocols.html</id>
    <published>2019-02-19T00:00:00+00:00</published>
    <updated>2019-02-19T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">An introduction to writing expressive and intuitive Elixir code with Protocols.</summary>
    <content type="html">&lt;p&gt;In today&amp;#39;s Elixir Alchemy, we will stir into the potion of protocols. Elixir has several mechanisms that allow us to write expressive and intuitive code.&lt;/p&gt;
&lt;p&gt;Pattern matching, for instance, is a powerful way of dealing with multiple scenarios without having to go into complicated branching. It allows each of our functions to be clear and concise.&lt;/p&gt;
&lt;h1&gt;What Are Protocols?&lt;/h1&gt;
&lt;p&gt;In a way, Protocols are similar to pattern matching, but they allow us to write more meaningful and context-specific code based on the datatype we’re dealing with.&lt;/p&gt;
&lt;p&gt;Let’s take the example of a content-delivery website. This website has multiple types of content: audio clips, videos, texts, and whatever else you can think of.&lt;/p&gt;
&lt;p&gt;Each of these content types obviously has different attributes and metadata, so it makes sense for them to be represented by independent structs:&lt;/p&gt;
&lt;p&gt;Translating this into Elixir, you’d have the following structures:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Content.Audio do
  defstruct [:title, :album, :artist, :duration, :bitrate, :file]
end

defmodule Content.Video do
  defstruct [:title, :cast, :release_date, :duration, :resolution, :file]
end

defmodule Content.Text do
  defstruct [:title, :author, :word_count, :chapter_count, :format, :file]
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of these types has a few different fields, most of them unique to the type. We also have a common &lt;code&gt;:file&lt;/code&gt; field which will point to the file keeping the actual data.&lt;/p&gt;
&lt;p&gt;Now, let’s say you want to make your content as accessible as possible. You may, for instance, want to allow your hearing-impaired users to view the transcripts of both your audio and video. For that, you’ll use your awesome &lt;code&gt;AudioTranscriber&lt;/code&gt; and &lt;code&gt;VideoTranscriber&lt;/code&gt; modules which provide &lt;code&gt;transcribe_audio/1&lt;/code&gt; and &lt;code&gt;transcribe_video/1&lt;/code&gt; functions, respectively.&lt;/p&gt;
&lt;p&gt;The implementation of those functions uses state-of-the-art machine learning and will be delegated to a future blog post. Let’s just assume they work and roll with it.&lt;/p&gt;
&lt;p&gt;Both transcriber modules are split up into separate modules. Aside from having different function names for transcribing content, they might be completely different libraries. To allow us to use both in a transparent manner, we&amp;#39;ll implement a protocol named &lt;code&gt;Content.Transcribe&lt;/code&gt; that has a unified API that can handle both types of content.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h1&gt;Implementing the Protocol&lt;/h1&gt;
&lt;p&gt;Using protocols, we can easily define what the act of transcribing something means to each of our data types. This is done by first defining a transcribing protocol:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defprotocol Content.Transcribe do
  def transcribe(content)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then implementing it separately for each of our types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defimpl Content.Transcribe, for: Content.Video do
  def transcribe(video), do: VideoTranscriber.transcribe_video(video.file)
end

defimpl Content.Transcribe, for: Content.Audio do
  def transcribe(audio), do: AudioTranscriber.transcribe_audio(audio.file)
end

defimpl Content.Transcribe, for: Content.Text do
  def transcribe(text), do: File.read(text.file)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have separately defined implementations of the same function for all 3 content types.&lt;/p&gt;
&lt;p&gt;You may note that for text content, the implementation merely reads the corresponding file, as it&amp;#39;s already in text format, while for the other two, we call the corresponding machine-learning-magic function on the file.&lt;/p&gt;
&lt;p&gt;We’re then able to call &lt;code&gt;transcribe/1&lt;/code&gt; for all the data types we have an implementation for:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex&amp;gt; %Content.Video{...} |&amp;gt; Content.Transcribe.transcribe()
{:ok, &amp;quot;We&amp;#39;re no strangers to love\nYou know the rules and so do I...&amp;quot;}

iex&amp;gt; %Content.Audio{...} |&amp;gt; Content.Transcribe.transcribe()
{:ok, &amp;quot;Imagine there&amp;#39;s no heaven\nIt&amp;#39;s easy if you try...&amp;quot;}

iex&amp;gt; %Content.Text{...} |&amp;gt; Content.Transcribe.transcribe()
{:ok, &amp;quot;in a hole in the ground there lived a hobbit...&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Fallback Implementations&lt;/h1&gt;
&lt;p&gt;Now, let’s say we add a new type of media to our platform: games (we’re kidding! We are a very ambitious hypothetical startup, and admittedly, success may be getting into our heads).&lt;/p&gt;
&lt;p&gt;What happens when we try to transcribe the newly-added content?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex&amp;gt; %Content.Game{...} |&amp;gt; Content.Transcribe.transcribe()
** (Protocol.UndefinedError) protocol Content.Transcribe is not implemented for %Content.Game{...}. This protocol is implemented for: Content.Audio, Content.Text, Content.Video
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whoops! We’ve hit an error. Which makes sense. We didn’t provide any transcription implementation for this type.&lt;/p&gt;
&lt;p&gt;But it doesn’t really make sense to do so, does it? Games are supposed to be interactive experiences, and there simply may be no way to make them accessible to everyone.&lt;/p&gt;
&lt;p&gt;So we could just provide an implementation that always fails:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defimpl Content.Transcribe, for: Content.Game do
  def transcribe(game), do: {:error, &amp;quot;not supported&amp;quot;}
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this doesn’t seem very scalable, does it? If we keep adding new content types, we&amp;#39;ll end up having to duplicate this for every single type that we cannot transcribe.&lt;/p&gt;
&lt;p&gt;Instead, we can simply add a fallback implementation for any type we don’t specify. This is done precisely by providing an implementation for the &lt;code&gt;Any&lt;/code&gt; type, and then stating in our protocol that we want to fall back to it when necessary.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defimpl Content.Transcribe, for: Any do
  def transcribe(_), do: {:error, &amp;quot;not supported&amp;quot;}
end

defprotocol Content.Transcribe do
  @fallback_to_any true
  def transcribe(content)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The implementation for &lt;code&gt;Any&lt;/code&gt; can usually be used by asking Elixir to automatically derive implementations from it (you can read more about this in the official &lt;a href=&quot;https://elixir-lang.org/getting-started/protocols.html#deriving&quot;&gt;Elixir Getting Started guide&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;But by adding &lt;code&gt;@fallback_to_any true&lt;/code&gt; to our protocol, we’re stating that whenever a specific implementation is not found, the &lt;code&gt;Any&lt;/code&gt; implementation should be used. This allows us to fail gracefully for any unsupported data type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex&amp;gt; %Content.Game{...} |&amp;gt; Content.Transcribe.transcribe()
{:error, &amp;quot;not supported&amp;quot;}

iex&amp;gt; %{key: :value} |&amp;gt; Content.Transcribe.transcribe()
{:error, &amp;quot;not supported&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Failed Gracefully&lt;/h1&gt;
&lt;p&gt;Can we close off any better than with a graceful fail? We&amp;#39;ll leave you now that we&amp;#39;ve experimented with protocols and we gracefully haven&amp;#39;t broken any alembic today.&lt;/p&gt;
&lt;p&gt;If you love experimenting with code, make sure you &lt;a href=&quot;/elixir-alchemy&quot;&gt;don&amp;#39;t miss an episode of Elixir Alchemy&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Serving Plug - Building an Elixir HTTP server from scratch</title>
    <link rel="alternate" href="https://blog.appsignal.com/2019/01/22/serving-plug-building-an-elixir-http-server.html"/>
    <id>https://blog.appsignal.com/2019/01/22/serving-plug-building-an-elixir-http-server.html</id>
    <published>2019-01-22T00:00:00+00:00</published>
    <updated>2019-01-22T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">It’s time for another Elixir Alchemy! We&#039;ll learn by building today. We&#039;re building an HTTP server with a Plug adapter, which parses requests and builds responses so it can run Plug apps.</summary>
    <content type="html">&lt;p&gt;Welcome back to another edition of Elixir Alchemy! In our continued quest to find out what’s happening under the hood, we&amp;#39;ll take a deep dive into HTTP servers in Elixir.&lt;/p&gt;
&lt;p&gt;To understand how HTTP servers work, we&amp;#39;ll implement a minimal example of one that can run a Plug application. We’ll learn about decoding requests and encoding responses, as well as how Plug interacts with the web server by building a minimal subset of an HTTP server that can accept HTTP requests and run a Plug application.&lt;/p&gt;
&lt;p&gt;-&amp;gt; The HTTP server we’re building is for educational purposes. We won’t build a production-ready HTTP server. If you&amp;#39;re looking for one that is, please try &lt;a href=&quot;https://github.com/ninenines/cowboy&quot;&gt;cowboy&lt;/a&gt;, which is the default choice of HTTP server in Elixir applications.&lt;/p&gt;
&lt;h2&gt;HTTP over TCP&lt;/h2&gt;
&lt;p&gt;We’ll start with the fundamentals. HTTP is a protocol that commonly uses &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_Control_Protocol&quot;&gt;TCP&lt;/a&gt; to transport requests and responses between an HTTP client—like a web browser—and a web server.&lt;/p&gt;
&lt;p&gt;Erlang provides the &lt;code&gt;:gen_tcp&lt;/code&gt; module that can be used to start a TCP socket that receives and transmits data. We&amp;#39;ll use that library as the basis of our server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http.ex
defmodule Http do
  require Logger

  def start_link(port: port) do
    {:ok, socket} = :gen_tcp.listen(port, active: false, packet: :http_bin, reuseaddr: true)
    Logger.info(&amp;quot;Accepting connections on port #{port}&amp;quot;)

    {:ok, spawn_link(Http, :accept, [socket])}
  end

  def accept(socket) do
    {:ok, request} = :gen_tcp.accept(socket)

    spawn(fn -&amp;gt;
      body = &amp;quot;Hello world! The time is #{Time.to_string(Time.utc_now())}&amp;quot;

      response = &amp;quot;&amp;quot;&amp;quot;
      HTTP/1.1 200\r
      Content-Type: text/html\r
      Content-Length: #{byte_size(body)}\r
      \r
      #{body}
      &amp;quot;&amp;quot;&amp;quot;

      send_response(request, response)
    end)

    accept(socket)
  end

  def send_response(socket, response) do
    :gen_tcp.send(socket, response)
    :gen_tcp.close(socket)
  end

  def child_spec(opts) do
    %{id: Http, start: {Http, :start_link, [opts]}}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we’ve created a TCP server that responds to every request with the current time in an HTTP response.&lt;/p&gt;
&lt;p&gt;We start a socket to listen to the passed in port in &lt;code&gt;start_link/1&lt;/code&gt;, and we&amp;#39;ll spawn &lt;code&gt;accept/1&lt;/code&gt; in a new process that waits until a request comes in over the socket by calling &lt;code&gt;:gen_tcp.accept/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When it does, we put it into the &lt;code&gt;request&lt;/code&gt; variable and create a response to send to the client. In this case, we&amp;#39;ll be sending a response that shows the current time.&lt;/p&gt;
&lt;div className=&quot;header ruby_magic&quot;&gt;
  &lt;h3&gt;Building HTTP responses&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;HTTP/1.1 200\r\nContent-Type: text/html\r\n\r\n\Hello world! The time is
14:45:49.058045
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An HTTP response contains a couple of parts:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;A status line, with the protocol version (&lt;code&gt;HTTP/1.1&lt;/code&gt;) and a response code (&lt;code&gt;200&lt;/code&gt;)&lt;/li&gt;
    &lt;li&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Carriage_return&quot;&gt;carriage return&lt;/a&gt;, followed by a &lt;a href=&quot;https://en.wikipedia.org/wiki/Newline&quot;&gt;line feed&lt;/a&gt; (&lt;code&gt;\r\n&lt;/code&gt;) to split the status line from the rest of the response&lt;/li&gt;
    &lt;li&gt;(Optional) header lines (&lt;code&gt;Content-Type: text/html&lt;/code&gt;), separated by CRLFs&lt;/li&gt;
    &lt;li&gt;A double CRLF, to separate the headers from the response body&lt;/li&gt;
    &lt;li&gt;The response body that will be shown in the browser (&lt;code&gt;Hello world! The time is 14:45:49.058045&lt;/code&gt;)&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;We pass the body we built to &lt;code&gt;send_response/2&lt;/code&gt;, which takes care of sending the response over the socket and finally closing the socket connection.&lt;/p&gt;
&lt;p&gt;We spawn a process for each request so the server can call &lt;code&gt;accept/1&lt;/code&gt; again to accept new requests. This way, we can respond to requests in parallel, instead of subsequent requests having to wait for previous ones to complete being processed.&lt;/p&gt;
&lt;h2&gt;Running the Server&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s try it out. We&amp;#39;ll use a &lt;a href=&quot;/2017/08/10/elixir-alchemy-supervisors-building-fault-tolerant-elixir-applications.html&quot;&gt;supervisor&lt;/a&gt; to run our HTTP server to make sure it&amp;#39;s restarted immediately when if it fails.&lt;/p&gt;
&lt;p&gt;Our server implementation has a &lt;code&gt;child_spec/1&lt;/code&gt; function that specifies how it should be started. It states that it should call the &lt;code&gt;Http.start/1&lt;/code&gt; function with the passed options, which will return the newly spawned process&amp;#39; ID.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http.ex
defmodule Http do
  # ...

  def child_spec(opts) do
    %{id: Http, start: {Http, :start_link, [opts]}}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because of that, we can add it to the list of children managed by the supervisor in &lt;code&gt;lib/http/application.ex&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http/application.ex
defmodule Http.Application do
  @moduledoc false
  use Application

  def start(_type, _args) do
    children = [
      {Http, port: 8080}
    ]

    opts = [strategy: :one_for_one, name: Http.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We pass &lt;code&gt;{Http, port: 8080}&lt;/code&gt; as one of our supervisor&amp;#39;s children to start the server at port 8080 when the application is started.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ mix run --no-halt
19:39:29.454 [info]  Accepting connections on port 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we start the server and use our browser to send a request, we can see that it indeed returns the current time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2019-01/http_1.png&quot; alt=&quot;A screenshot of our Elixir HTTP server displaying the current time.&quot;/&gt;&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Plug&lt;/h2&gt;
&lt;p&gt;Now that we know how a web server works, let&amp;#39;s take it to the next level. Our current implementation has the response hard-coded into the server. To allow our web server to run different apps, we&amp;#39;ll move the app out into a separate &lt;a href=&quot;https://github.com/elixir-plug/plug&quot;&gt;Plug&lt;/a&gt; module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/current_time.ex
defmodule CurrentTime do
  import Plug.Conn

  def init(options), do: options

  def call(conn, _opts) do
    conn
    |&amp;gt; put_resp_content_type(&amp;quot;text/html&amp;quot;)
    |&amp;gt; send_resp(200, &amp;quot;Hello world! The time is #{Time.to_string(Time.utc_now())}&amp;quot;)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;CurrentTime&lt;/code&gt; module defines a &lt;code&gt;call/2&lt;/code&gt; function that takes the passed in &lt;code&gt;%Plug.Conn&lt;/code&gt; struct. It then sets the response content type to &amp;quot;text/html&amp;quot; before sending the &amp;quot;Hello world!&amp;quot; message—together with the current time—back as a response.&lt;/p&gt;
&lt;p&gt;Our new module behaves the same as the web server example, but it&amp;#39;s detached from the web server. Because of Plug, we could swap out servers without having to change the application&amp;#39;s code, and we can also change the application without having to touch the web server.&lt;/p&gt;
&lt;h3&gt;Writing a Plug Adapter&lt;/h3&gt;
&lt;p&gt;To make sure our web server can communicate with our web application, we need to build a &lt;code&gt;%Plug.Conn{}&lt;/code&gt; struct to pass to &lt;code&gt;CurrentTime.call/2&lt;/code&gt;. We&amp;#39;ll also need to turn the sent response into a string that our web server can send back over the socket.&lt;/p&gt;
&lt;p&gt;To do this, we&amp;#39;ll create an adapter that handles the communication between our Plug app and our web server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http/adapter.ex
defmodule Http.PlugAdapter do
  def dispatch(request, plug) do
    %Plug.Conn{
      adapter: {Http.PlugAdapter, request},
      owner: self()
    }
    |&amp;gt; plug.call([])
  end

  def send_resp(socket, status, headers, body) do
    response = &amp;quot;HTTP/1.1 #{status}\r\n#{headers(headers)}\r\n#{body}&amp;quot;

    Http.send_response(socket, response)
    {:ok, nil, socket}
  end

  def child_spec(plug: plug, port: port) do
    Http.child_spec(port: port, dispatch: &amp;amp;dispatch(&amp;amp;1, plug))
  end

  defp headers(headers) do
    Enum.reduce(headers, &amp;quot;&amp;quot;, fn {key, value}, acc -&amp;gt;
      acc &amp;lt;&amp;gt; key &amp;lt;&amp;gt; &amp;quot;: &amp;quot; &amp;lt;&amp;gt; value &amp;lt;&amp;gt; &amp;quot;\n\r&amp;quot;
    end)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of responding directly from &lt;code&gt;Http.accept/2&lt;/code&gt;, we&amp;#39;ll use our adapter&amp;#39;s &lt;code&gt;dispatch/2&lt;/code&gt; function to build a &lt;code&gt;%Plug.Conn{}&lt;/code&gt; struct and pass that to our plug&amp;#39;s &lt;code&gt;call/2&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;%Plug.Conn{}&lt;/code&gt;, we&amp;#39;ll set the &lt;code&gt;:adapter&lt;/code&gt; to link to our Adapter module, and then pass the socket the response that should be sent over. This ensures that the Plug app knows which module to call &lt;code&gt;send_resp/4&lt;/code&gt; on.&lt;/p&gt;
&lt;p&gt;Our adapter&amp;#39;s &lt;code&gt;send_resp/4&lt;/code&gt; takes the socket connection, the response status, a list of headers and a body, which are all prepared by the Plug application. It uses the passed in arguments to build the response and calls out to &lt;code&gt;Http.send_response/2&lt;/code&gt; that we&amp;#39;ve implemented before.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;child_spec/1&lt;/code&gt; for our adapter returns the &lt;code&gt;child_spec/1&lt;/code&gt; for the &lt;code&gt;Http&lt;/code&gt; module. This causes the web server to start when we supervise our adapter. We&amp;#39;ll pass the dispatch function as the dispatch so that it can be called by our web server when it receives a response.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http/application.ex
defmodule Http.Application do
  @moduledoc false
  use Application

  def start(_type, _args) do
    children = [
      {Http.PlugAdapter, plug: CurrentTime, port: 8080}
    ]

    opts = [strategy: :one_for_one, name: Http.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of starting &lt;code&gt;Http&lt;/code&gt; in our application module, we&amp;#39;ll start &lt;code&gt;Http.PlugAdapter&lt;/code&gt;, which will take care of setting the plug, preparing the dispatch function and starting the web server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http.ex
defmodule Http do
  require Logger

  def start_link(port: port, dispatch: dispatch) do
    {:ok, socket} = :gen_tcp.listen(port, active: false, packet: :http_bin, reuseaddr: true)
    Logger.info(&amp;quot;Accepting connections on port #{port}&amp;quot;)

    {:ok, spawn_link(Http, :accept, [socket, dispatch])}
  end

  def accept(socket, dispatch) do
    {:ok, request} = :gen_tcp.accept(socket)

    spawn(fn -&amp;gt;
      dispatch.(request)
    end)

    accept(socket, dispatch)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we now handle requests in our Plug, we can remove most of the code in &lt;code&gt;Http.accept/2&lt;/code&gt;. The &lt;code&gt;Http.start_link/2&lt;/code&gt; function will now receive the dispatch function from the adapter, which is used to send the request to in &lt;code&gt;Http.accept/2&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ mix run --no-halt
19:39:29.454 [info]  Accepting connections on port 8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running the server again, everything still works exactly as before. However, our HTTP server, web application and Plug adapter are now three separate modules.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2019-01/http_2.png&quot; alt=&quot;A screenshot of our Elixir HTTP server displaying the current time.&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Swapping out Plug Applications&lt;/h2&gt;
&lt;p&gt;Because our server is now separate from our adapter and web application, we can swap the Plug out to run another application on the server. Let&amp;#39;s give that a shot.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# mix.exs
defmodule Http.MixProject do
  # ...

  defp deps do
    [
      {:plug_octopus, github: &amp;quot;jeffkreeftmeijer/plug_octopus&amp;quot;},
      {:plug, &amp;quot;~&amp;gt; 1.7&amp;quot;}
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In our &lt;code&gt;mix.exs&lt;/code&gt; file, we add &lt;code&gt;:plug_octopus&lt;/code&gt; as a dependency.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http/application.ex
defmodule Http.Application do
  @moduledoc false
  use Application

  def start(_type, _args) do
    children = [
      {Http.PlugAdapter, plug: Plug.Octopus, port: 8080}
    ]

    opts = [strategy: :one_for_one, name: Http.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then swap &lt;code&gt;CurrentTime&lt;/code&gt; for &lt;code&gt;Plug.Octopus&lt;/code&gt; in our &lt;code&gt;Http.Application&lt;/code&gt; module. Starting the server and visiting &lt;a href=&quot;http://localhost:8080&quot;&gt;http://localhost:8080&lt;/a&gt; now shows an octopus!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2019-01/octopus_1.png&quot; alt=&quot;A screenshot of our Elixir HTTP server running Plug.Octopus.&quot;/&gt;&lt;/p&gt;
&lt;p&gt;However, clicking the &lt;em&gt;flip!&lt;/em&gt; and &lt;em&gt;crash!&lt;/em&gt; buttons doesn&amp;#39;t do anything and any URL that&amp;#39;s called shows the same page. That&amp;#39;s because we skipped over parsing the requests altogether. Since we don&amp;#39;t read the requests, we&amp;#39;ll always pass the same response back. Let&amp;#39;s fix that.&lt;/p&gt;
&lt;h2&gt;Parsing Requests&lt;/h2&gt;
&lt;p&gt;To read requests, we&amp;#39;ll need to read the response from the socket. Thanks to the &lt;code&gt;http_bin&lt;/code&gt; option that we&amp;#39;re passing when calling &lt;code&gt;:gen_tcp.listen/2&lt;/code&gt;, the request is returned in a format we can pattern match on.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http.ex
defmodule Http do
  # ...

  def read_request(request, acc \\ %{headers: []}) do
    case :gen_tcp.recv(request, 0) do
      {:ok, {:http_request, :GET, {:abs_path, full_path}, _}} -&amp;gt;
        read_request(request, Map.put(acc, :full_path, full_path))

      {:ok, :http_eoh} -&amp;gt;
        acc

      {:ok, {:http_header, _, key, _, value}} -&amp;gt;
        read_request(
          request,
          Map.put(acc, :headers, [{String.downcase(to_string(key)), value} | acc.headers])
        )

      {:ok, line} -&amp;gt;
        read_request(request, acc)
    end
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Http.read_request/2&lt;/code&gt; function takes a socket connection and will be called from the dispatch function. It will keep calling &lt;code&gt;:gen_tcp.recv/2&lt;/code&gt; to accept lines from the request until it receives an &lt;code&gt;:http_eoh&lt;/code&gt; response, indicating the end of the requests headers.&lt;/p&gt;
&lt;p&gt;We match on the &lt;code&gt;:http_request&lt;/code&gt; line, which includes the full request path. We&amp;#39;ll use that to extract the path and URL parameters later. We&amp;#39;ll also match on all &lt;code&gt;:http_header&lt;/code&gt; lines, which we convert to a list we can pass to our Plug application later.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/http/adapter.ex
defmodule Http.PlugAdapter do
  def dispatch(request, plug) do
    %{full_path: full_path} = Http.read_request(request)

    %Plug.Conn{
      adapter: {Http.PlugAdapter, request},
      owner: self(),
      path_info: path_info(full_path),
      query_string: query_string(full_path)
    }
    |&amp;gt; plug.call([])
  end

  # ...

  defp headers(headers) do
    Enum.reduce(headers, &amp;quot;&amp;quot;, fn {key, value}, acc -&amp;gt;
      acc &amp;lt;&amp;gt; key &amp;lt;&amp;gt; &amp;quot;: &amp;quot; &amp;lt;&amp;gt; value &amp;lt;&amp;gt; &amp;quot;\n\r&amp;quot;
    end)
  end

  defp path_info(full_path) do
    [path | _] = String.split(full_path, &amp;quot;?&amp;quot;)
    path |&amp;gt; String.split(&amp;quot;/&amp;quot;) |&amp;gt; Enum.reject(&amp;amp;(&amp;amp;1 == &amp;quot;&amp;quot;))
  end

  defp query_string([_]), do: &amp;quot;&amp;quot;
  defp query_string([_, query_string]), do: query_string

  defp query_string(full_path) do
    full_path
    |&amp;gt; String.split(&amp;quot;?&amp;quot;)
    |&amp;gt; query_string
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We call &lt;code&gt;Http.read_request/1&lt;/code&gt; from &lt;code&gt;Http.PlugAdapter.dispatch/2&lt;/code&gt;. Having the &lt;code&gt;full_path&lt;/code&gt;, we can extract the &lt;code&gt;path_info&lt;/code&gt; (a list of path segments), and &lt;code&gt;query_string&lt;/code&gt; (all URL parameters after the &amp;quot;?&amp;quot;). We add these to the &lt;code&gt;%Plug.Conn{}&lt;/code&gt; to have our Plug app handle the rest.&lt;/p&gt;
&lt;p&gt;Restarting the server, we can now flip and crash the lobster.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2019-01/octopus_2.png&quot; alt=&quot;A screenshot of our Elixir HTTP server running Plug.Octopus and accepting URL parameters.&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;A Minimal Web Server Example that flips and crashes&lt;/h2&gt;
&lt;p&gt;With everyone in place, and no screws on the floor, our project to look into HTTP servers in Elixir is done. We&amp;#39;ve implemented a web server that extracts data from requests and used it to send a request to a Plug application. It even has concurrency included: since each request spawns a separate process, our web server can handle multiple concurrent users.&lt;/p&gt;
&lt;p&gt;There&amp;#39;s more to HTTP servers than we&amp;#39;ve shown in this article, but we hope implementing one from the ground up gave you some insight into how a web server could work.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&quot;https://github.com/jeffkreeftmeijer/elixir-http-server&quot;&gt;the finished project&lt;/a&gt; if you&amp;#39;d like to review the code, and don&amp;#39;t forget to &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;subscribe to the mailing list&lt;/a&gt; if you&amp;#39;d like to read more Elixir Alchemy!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Understanding Elixir’s GenStages - Querying the Blockchain</title>
    <link rel="alternate" href="https://blog.appsignal.com/2018/11/13/elixir-alchemy-understanding-elixirs-genstages-querying-the-blockchain.html"/>
    <id>https://blog.appsignal.com/2018/11/13/elixir-alchemy-understanding-elixirs-genstages-querying-the-blockchain.html</id>
    <published>2018-11-13T00:00:00+00:00</published>
    <updated>2018-11-13T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">A dive into Elixir&#039;s GenStage module and backpressure using an example querying the blockchain</summary>
    <content type="html">&lt;p&gt;In this edition of Elixir Alchemy, we&amp;#39;ll dive into Elixir&amp;#39;s GenStage module. Along the way, we&amp;#39;ll explain backpressure and we&amp;#39;ll write a Genstage to query the blockchain. Let&amp;#39;s start by discussing how using a GenStage can solve buffering problems.&lt;/p&gt;
&lt;h1&gt;What Is a GenStage?&lt;/h1&gt;
&lt;p&gt;Imagine you’re consuming data from an external source. That source could be anything “streamable” - such as reading a file line-by-line, a table in a database, or even a sequence of requests to a 3rd party API.&lt;/p&gt;
&lt;p&gt;In such scenarios, where you need to stream data into your system, and probably do some processing on each data point, it’s common to use a buffer to read in a few items, process the whole batch, and then fetch a new set into the buffer. I remember, from the time I was learning C/C++, that this would be a common, although arguably naive way to do things.&lt;/p&gt;
&lt;p&gt;With that approach, you may run into one of two problems: the buffer can get too small, or the buffer van get too large.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buffer Too Small&lt;/strong&gt;
This happens if you read too few items at a time. Since you’re switching back and forth between reading and processing items, there will be a performance cost from the task switching. In the example of reading a file, your hardware or Operating System may be reading more data than what you’re actually requesting, resulting in sub-optimal performance, in addition to having to fetch the same part of the file later on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buffer Too Large&lt;/strong&gt;
In this case, you request too much from your data source. You may end up either creating a bottleneck (e.g. having to wait for your hard drive to read everything you requested), or not being able to process all the data in an efficient manner. If you’ve ever heard of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Buffer_overflow&quot;&gt;buffer overflow&lt;/a&gt; (a common performance and security concern), this is it. You’re reading more than what your system can keep up with, resulting in all kinds of problems, from performance to actual failures.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Solution: Backpressure&lt;/h2&gt;
&lt;p&gt;The term &lt;em&gt;backpressure&lt;/em&gt; refers to the behavior of a system that builds up input, then halts the receiving of new data once the buffer is full, resuming it once again when the system is ready to handle it.&lt;/p&gt;
&lt;p&gt;This is the core idea behind Elixir’s GenStage.&lt;/p&gt;
&lt;h1&gt;GenStage&lt;/h1&gt;
&lt;p&gt;GenStage is an abstraction built on top of GenServer to provide a simple way to create a Producer/Consumer architecture, while automatically managing the concept of backpressure.&lt;/p&gt;
&lt;p&gt;In a GenStage, you create a pipeline of multiple Producers &amp;amp; Consumers. Producers generate data points, or read them from a source, and then pass them down to the pipeline. They can then be sent through one or more Consumers that will do whatever processing you need done.&lt;/p&gt;
&lt;p&gt;The idea of backpressure is applied in the way items are created in a Producer. When the pipeline is ready to receive new items, the &lt;code&gt;handle_demand/2&lt;/code&gt; function of the Producer is called, requesting a specific amount of items.&lt;/p&gt;
&lt;p&gt;The amount requested is decided internally (although you can specify a maximum value), and the function is called whenever there is room for them in the pipeline. If items take too long to process, Producers end up being idle for a while, thus relieving some pressure from the system.&lt;/p&gt;
&lt;h1&gt;Use Case&lt;/h1&gt;
&lt;p&gt;As an example of what a GenStage can be useful for, let’s consider reading chunks of data from an external data source. In this case, we’ll use the &lt;a href=&quot;https://www.ethereum.org/&quot;&gt;Ethereum&lt;/a&gt; blockchain, since it fits this concept nicely.&lt;/p&gt;
&lt;p&gt;A blockchain is composed of a series of blocks, each one containing multiple transactions. If we want to process the entire blockchain (for example, to look up all transactions involving a given address, or to listen to it continuously when integrating with your application), a GenStage is a perfect fit.&lt;/p&gt;
&lt;p&gt;In this context, each block can be considered as a single data item. Let’s see how this can be achieved.&lt;/p&gt;
&lt;h2&gt;Querying the Blockchain&lt;/h2&gt;
&lt;p&gt;We’re going to use &lt;a href=&quot;https://infura.io/&quot;&gt;Infura’s&lt;/a&gt; public HTTP API to interact with the Ethereum blockchain. Let’s start by building a wrapper to its interface. I’ll be using the &lt;a href=&quot;https://github.com/teamon/tesla&quot;&gt;Tesla&lt;/a&gt; library for this (this is just a personal preference, feel free to choose your own).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EthSync.Infura do
  use Tesla

  plug(Tesla.Middleware.BaseUrl, &amp;quot;https://ropsten.infura.io/&amp;quot;)

  # encode/decode body as json
  # Infura doesn&amp;#39;t set the &amp;quot;content-type&amp;quot; header to &amp;quot;application/json&amp;quot;
  # so we need to tell Tesla that we want text/plain requests to be decoded as well
  plug(Tesla.Middleware.JSON, decode_content_types: [&amp;quot;text/plain; charset=utf-8&amp;quot;])

  @doc &amp;quot;Get an entire block&amp;quot;
  def get_block(number) do
    case call(:eth_getBlockByNumber, [to_hex(number), true]) do
      {:ok, nil} -&amp;gt;
        {:error, :block_not_found}

      error -&amp;gt;
        error
    end
  end

  @doc &amp;quot;Sends a JSON-RPC call to the server&amp;quot;
  defp call(method, params \\ []) do
    case post(&amp;quot;&amp;quot;, %{jsonrpc: &amp;quot;2.0&amp;quot;, id: &amp;quot;call_id&amp;quot;, method: method, params: params}) do
      {:ok, %Tesla.Env{status: 200, body: %{&amp;quot;result&amp;quot; =&amp;gt; result}}} -&amp;gt;
        {:ok, result}

      {:error, _} = error -&amp;gt;
        error
    end
  end

  @doc &amp;quot;Converts integer values to hex strings&amp;quot;
  def to_hex(decimal), do: &amp;quot;0x&amp;quot; &amp;lt;&amp;gt; Integer.to_string(decimal, 16)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;We’ll only need a single endpoint for this: getting a block’s data, given its index on the chain. The block number must be given in hexadecimal format, so we also need a helper method to handle the conversion.&lt;/p&gt;
&lt;p&gt;We can verify that this is working via &lt;code&gt;iex&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; EthSync.Infura.get_block(1)
{:ok,
 %{
   &amp;quot;number&amp;quot; =&amp;gt; &amp;quot;0x1&amp;quot;,
   &amp;quot;transactions&amp;quot; =&amp;gt; [],
   # ...
 }
}

iex(2)&amp;gt; EthSync.Infura.get_block(1_000_000_000_000)
{:error, :block_not_found}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building the Producer&lt;/h2&gt;
&lt;p&gt;Our Producer will be a process with the responsibility of fetching Ethereum blocks.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EthSync.Producer2 do
  alias EthSync.Infura
  use GenStage

  def init(_) do
    {:producer, 1}
  end

  def handle_demand(demand, next_block) when demand &amp;gt; 0 do
    IO.puts(&amp;quot;Demanding #{demand}&amp;quot;)

    blocks =
      next_block..(next_block - 1 + demand)
      |&amp;gt; Enum.map(fn n -&amp;gt;
        IO.puts(&amp;quot;Fetching block #{n}&amp;quot;)
        Infura.get_block(n)
      end)

    {:noreply, blocks, next_block + length(blocks)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building the Consumer&lt;/h2&gt;
&lt;p&gt;The Consumer will receive lists of blocks and then process them. In the example, we’ll use &lt;code&gt;:timer.sleep/1&lt;/code&gt; to simulate processing time since we’re not doing any actual work. Keep in mind that the list of blocks received is not necessarily the same as what was sent in the Producer. Items can be buffered according to the GenStage’s internal rules. It may also happen that you have multiple Consumers and items get split between them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule EthSync.Consumer do
  alias EthSync.Infura
  use GenStage

  def init(_) do
    {:consumer, nil}
  end

  def handle_events(blocks, _from, state) do
    blocks
    |&amp;gt; Enum.each(fn
      {:ok, %{&amp;quot;number&amp;quot; =&amp;gt; n}} -&amp;gt;
        IO.puts(&amp;quot;Received block #{n}&amp;quot;)
        :timer.sleep(1_000)
    end)

    {:noreply, [], state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Wiring It All Up&lt;/h2&gt;
&lt;p&gt;To start the pipeline, we need to start the processes for our Producer &amp;amp; Consumer, and then link them together, so that items produced by the former get sent out to the latter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; {:ok, producer} = GenStage.start_link(Producer2, [])
{:ok, #PID&amp;lt;0.160.0&amp;gt;}

iex&amp;gt; {:ok, consumer} = GenStage.start_link(Consumer2, [])
{:ok, #PID&amp;lt;0.162.0&amp;gt;}

iex&amp;gt; GenStage.sync_subscribe(consumer, to: producer, max_demand: 3)
{:ok, #Reference&amp;lt;0.2486793675.579338241.116277&amp;gt;}
Demanding 3
Received block 0x1
Received block 0x2
Received block 0x3
Demanding 1
Received block 0x4
Received block 0x5
Demanding 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that even though we start the Producer at the beginning, it only started fetching blocks once we wired the Consumer to it. That’s because there was no demand until that point. Additionally, even though we specify &lt;code&gt;max_demand: 3&lt;/code&gt;, that’s not necessarily the amount requested at all times. Since we only have a single Consumer, and it takes 1 second to process each block, the GenStage is smart enough not to overflow it with too many blocks. It adjusts the number of events as needed.&lt;/p&gt;
&lt;h2&gt;Consumed the coolness?&lt;/h2&gt;
&lt;p&gt;With the Producer, Consumer and having wired them together we&amp;#39;ve created a basic GenServer example. We love how GenStages provides an elegant way to create a producer/consumer architecture that automatically manages Backpressure.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post is written by guest author &lt;a href=&quot;http://naps62.github.io/&quot;&gt;Miguel Palhas&lt;/a&gt;. Miguel is a professional over-engineer &lt;a href=&quot;https://twitter.com/subvisual&quot;&gt;@subvisual&lt;/a&gt; and organizes &lt;a href=&quot;https://twitter.com/rubyconfpt&quot;&gt;@rubyconfpt&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mirrorconf&quot;&gt;@MirrorConf&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you&amp;#39;d love to read more Elixir Alchemy, be sure to &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;subscribe to the mailing list&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Hot Code Reloading in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2018/10/16/elixir-alchemy-hot-code-reloading-in-elixir.html"/>
    <id>https://blog.appsignal.com/2018/10/16/elixir-alchemy-hot-code-reloading-in-elixir.html</id>
    <published>2018-10-16T00:00:00+00:00</published>
    <updated>2018-10-16T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">How to upgrade code in a running Elixir application without restarting. 🏎</summary>
    <content type="html">&lt;p&gt;Through its roots in Erlang, Elixir&amp;#39;s robustness and reliability are often mentioned as its greatest advantages. The ultimate example of this being its ability to upgrade an application without having to restart it.&lt;/p&gt;
&lt;p&gt;Being one of Erlang&amp;#39;s most amazing features, &lt;em&gt;hot code reloading&lt;/em&gt; is sometimes compared to replacing the wheels on a driving car and it&amp;#39;s majestically demonstrated with phone calls and hot bug fixes in &lt;a href=&quot;https://www.youtube.com/watch?v=BXmOlCy0oBM&quot;&gt;Erlang: The Movie&lt;/a&gt;. But, how does it work under the hood?&lt;/p&gt;
&lt;p&gt;In this edition of Elixir Alchemy, we&amp;#39;ll dive into hot code reloading to see how Erlang&amp;#39;s code server handles seamless code upgrades in Elixir. To understand how all this works, we&amp;#39;ll start at the module level and work our way up. Let&amp;#39;s get started!&lt;/p&gt;
&lt;h2&gt;Upgrading Modules&lt;/h2&gt;
&lt;p&gt;The first part of the magic of hot code reloading is Erlang&amp;#39;s code server&amp;#39;s ability to run multiple versions of a module simultaneously. It allows existing processes to run to completion without having to be restarted or having their running code changed.&lt;/p&gt;
&lt;p&gt;To illustrate this, let&amp;#39;s look at an example of a module named &lt;code&gt;Counter&lt;/code&gt;. As the name implies, it counts up from 0 using a recursive function that sleeps for a second, prints the current number and calls itself with the number incremented by 1.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Counter do
  def count(n) do
    :timer.sleep(1000)
    IO.puts(&amp;quot;- #{inspect(self())}: #{n}&amp;quot;)
    count(n + 1)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After starting IEx (&lt;code&gt;$ iex -S mix&lt;/code&gt;), we spawn a process to start the counter loop in a separate process. We pass the module (&lt;code&gt;Counter&lt;/code&gt;), function name (&lt;code&gt;:count&lt;/code&gt;), and the arguments (&lt;code&gt;[0]&lt;/code&gt;) to the &lt;code&gt;spawn/3&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; spawn(Counter, :count, [0])
#PID&amp;lt;0.107.0&amp;gt;
- #PID&amp;lt;0.107.0&amp;gt;: 0
- #PID&amp;lt;0.107.0&amp;gt;: 1
- #PID&amp;lt;0.107.0&amp;gt;: 2
- #PID&amp;lt;0.107.0&amp;gt;: 3
…
iex(2)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While keeping the counter running, we update the counter module to increment the number by 2 instead of 1 in &lt;code&gt;lib/counter.ex&lt;/code&gt;. After that&amp;#39;s done and the file is saved, we recompile the module in the IEx session.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;…
- #PID&amp;lt;0.107.0&amp;gt;: 2
- #PID&amp;lt;0.107.0&amp;gt;: 3
iex(2)&amp;gt; r Counter
{:reloaded, Counter, [Counter]}
- #PID&amp;lt;0.107.0&amp;gt;: 4
- #PID&amp;lt;0.107.0&amp;gt;: 5
- #PID&amp;lt;0.107.0&amp;gt;: 6
…
iex(3)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The module gets recompiled, but the existing counter still increments by one, meaning the old version of the code is still running in this process. If we spawn a new process that runs a counter, it &lt;em&gt;will&lt;/em&gt; be incremented by two, thus it will be running the new version.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;…
- #PID&amp;lt;0.107.0&amp;gt;: 4
- #PID&amp;lt;0.107.0&amp;gt;: 5
- #PID&amp;lt;0.107.0&amp;gt;: 6
iex(3)&amp;gt; spawn(Counter, :count, [0])
#PID&amp;lt;0.114.0&amp;gt;
- #PID&amp;lt;0.107.0&amp;gt;: 7
- #PID&amp;lt;0.114.0&amp;gt;: 0
- #PID&amp;lt;0.107.0&amp;gt;: 8
- #PID&amp;lt;0.114.0&amp;gt;: 2
- #PID&amp;lt;0.107.0&amp;gt;: 9
- #PID&amp;lt;0.114.0&amp;gt;: 4
…
iex(5)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example shows Erlang&amp;#39;s code server in action. By keeping the old version of the module present, the first process (&lt;code&gt;#PID&amp;lt;0.107.0&amp;gt;&lt;/code&gt;) continues running as it did before, but newly spawned processes (&lt;code&gt;#PID&amp;lt;0.114.0&amp;gt;&lt;/code&gt;) automatically use the new version.&lt;/p&gt;
&lt;h3&gt;The Erlang Code Server&lt;/h3&gt;
&lt;p&gt;Erlang&amp;#39;s &lt;em&gt;code server&lt;/em&gt; handles loading compiled code in a running system. At any one time, the code server can keep two versions of a module in memory. When a module is loaded, it becomes the &lt;em&gt;current&lt;/em&gt; version of that module. If a previous version of that module was already present, it&amp;#39;s marked &lt;em&gt;old&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Both current and old versions of a module can run at the same time, but the exported functions from the old version are replaced by the ones from the new version. This ensures that every external function call always calls functions on the current version of the module.&lt;/p&gt;
&lt;p&gt;If a process is already running when a new version of a module is loaded, it will linger on the old version, and all of its local function calls will be handled by the module&amp;#39;s old version.&lt;/p&gt;
&lt;h2&gt;Hot Reloading GenServers&lt;/h2&gt;
&lt;p&gt;Let&amp;#39;s take this a step further by turning our example into a GenServer. Like the &lt;code&gt;Counter&lt;/code&gt; module in the previous example, the &lt;code&gt;CountServer&lt;/code&gt; counts up by incrementing its state every second.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CountServer do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, 0)
  end

  def init(state) do
    Process.send_after(self(), :increment, 1000)
    {:ok, state}
  end

  def handle_info(:increment, n) do
    incremented = n + 1
    IO.puts(&amp;quot;- #{inspect(self())}: #{incremented}&amp;quot;)

    Process.send_after(self(), :increment, 1000)

    {:noreply, incremented}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;Since the &lt;code&gt;CountServer&lt;/code&gt; is a GenServer, we don&amp;#39;t need to start it in a separate process manually. Instead, we call &lt;code&gt;CountServer.start_link/0&lt;/code&gt; in a new IEx session to start the counter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex(1)&amp;gt; {:ok, pid} = CountServer.start_link()
{:ok, #PID&amp;lt;0.130.0&amp;gt;}
- #PID&amp;lt;0.130.0&amp;gt;: 1
- #PID&amp;lt;0.130.0&amp;gt;: 2
- #PID&amp;lt;0.130.0&amp;gt;: 3
…
iex(2)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s try updating it like we did in the last example. We update the &lt;code&gt;CountServer&lt;/code&gt; to increment by 2 instead of one. Then, in the running IEx session, we recompile the module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;…
- #PID&amp;lt;0.130.0&amp;gt;: 2
- #PID&amp;lt;0.130.0&amp;gt;: 3
iex(2)&amp;gt; r CountServer
{:reloaded, CountServer, [CountServer]}
- #PID&amp;lt;0.130.0&amp;gt;: 5
- #PID&amp;lt;0.130.0&amp;gt;: 7
- #PID&amp;lt;0.130.0&amp;gt;: 9
…
iex(3)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This time, the running GenServer &lt;em&gt;did&lt;/em&gt; update. After recompiling the module, the counter started incrementing by 2 instead of one without having to be restarted or starting a new counter.&lt;/p&gt;
&lt;h3&gt;Local and External Function Calls&lt;/h3&gt;
&lt;p&gt;The first example had a recursive function spawned in a process, while the second had a GenServer which spawned a process to keep its state.&lt;/p&gt;
&lt;p&gt;As we learned while &lt;a href=&quot;/2018/06/12/elixir-alchemy-deconstructing-genservers.html&quot;&gt;deconstructing GenServers&lt;/a&gt;, the GenServer&amp;#39;s module and its spawned state are run in separate processes. In the second example, the state, which was kept in the GenServer process, was updated by calling out to the &lt;code&gt;CountServer&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;This difference is important for code reloading. &lt;em&gt;Local function calls&lt;/em&gt;, like the first example, in which a module calls its own function, are executed on the old version of the module. &lt;em&gt;External function calls&lt;/em&gt;, like the GenServer process calling out to the &lt;code&gt;CountServer&lt;/code&gt; module, are always done on the current version of the module.&lt;/p&gt;
&lt;p&gt;This explains why the first example didn&amp;#39;t reload the existing module, while the second one immediately did when the new module was loaded.&lt;/p&gt;
&lt;h2&gt;Transforming State&lt;/h2&gt;
&lt;p&gt;Although the state in the GenSever example got transformed correctly by the reloaded version of the &lt;code&gt;CountServer&lt;/code&gt; module, there&amp;#39;s one more scenario to look at. What happens when the new version of the implementation requires a different state?&lt;/p&gt;
&lt;p&gt;As an example, let&amp;#39;s say we need our &lt;code&gt;CountServer&lt;/code&gt; to only produce even numbers from now onward. Our current implementation increments by 2 every second, so most of the work is already done.&lt;/p&gt;
&lt;p&gt;However, if we have a process running that still increments by 1, we run the risk of upgrading at the wrong second, causing it to produce odd numbers instead. We need to make sure to update the state when we upgrade the module to the new version.&lt;/p&gt;
&lt;p&gt;Elixir&amp;#39;s &lt;code&gt;GenServer&lt;/code&gt; module has a callback named &lt;code&gt;code_change/3&lt;/code&gt;, that is used for updating the state in the event of a code change.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CountServer do
  use GenServer

  # ...

  def code_change(_old_vsn, state, _extra) when rem(state, 2) == 1 do
    {:ok, state - 1}
  end

  def code_change(_old_vsn, state, _extra) do
    {:ok, state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example implements the &lt;code&gt;code_change/3&lt;/code&gt; callback. If the state is an odd number, it will subtract 1 from the current state, making it an even number.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;_old_vsn&lt;/code&gt; argument holds the module&amp;#39;s old version that we&amp;#39;re upgrading from. It can be used to upgrade from a specific version, and the &lt;code&gt;_extra&lt;/code&gt; argument can be used for extra arguments while upgrading. For brevity, both of these are ignored here.&lt;/p&gt;
&lt;p&gt;To invoke the &lt;code&gt;code_change/3&lt;/code&gt; callback, we have to explicitly change the code for a process. To do that, we temporarily suspend the process, run the code change and resume it again.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;…
- #PID&amp;lt;0.130.0&amp;gt;: 7
- #PID&amp;lt;0.130.0&amp;gt;: 9
iex(3)&amp;gt; :sys.suspend(pid)
:ok
iex(4)&amp;gt; r CountServer
{:reloaded, CountServer, [CountServer]}
iex(5)&amp;gt; :sys.change_code(pid, CountServer, nil, [])
:ok
iex(6)&amp;gt; :sys.resume(pid)
:ok
- #PID&amp;lt;0.130.0&amp;gt;: 10
- #PID&amp;lt;0.130.0&amp;gt;: 12
- #PID&amp;lt;0.130.0&amp;gt;: 14
…
iex(3)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;: When releasing code, this is done automatically for each module in your app. There&amp;#39;s no need to explicitly call the &lt;code&gt;change_code/4&lt;/code&gt; function outside of IEx.&lt;/p&gt;
&lt;h2&gt;Backward Compatibility&lt;/h2&gt;
&lt;p&gt;Having external function calls executed on the new version of the module allows for gradual switching over to new versions of the modules in your app. Forcing processes that are lingering on old versions of modules to call out to the current version when doing external function calls ensures that the lingering processes don&amp;#39;t spawn even more lingering processes. However, mixing old and new code in a running system can cause problems when the new code is not backward compatible with the old modules.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s improve our counter a bit. Instead of hard coding the added value, we&amp;#39;ll allow it to be passed as an argument.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CountServer do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, 1)
  end

  def init(state) do
    send(self(), {:increment, 1})
    {:ok, state}
  end

  def handle_info({:increment, value}, state) do
    new_state = state + value
    IO.puts(new_state)
    Process.send_after(self(), {:increment, 1}, 1000)

    {:noreply, new_state}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example allows passing a value to increment by. We&amp;#39;ve also made sure to update both messages in &lt;code&gt;init/1&lt;/code&gt; and &lt;code&gt;handle_info/2&lt;/code&gt; to make sure they use the new format.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;- #PID&amp;lt;0.130.0&amp;gt;: 12
- #PID&amp;lt;0.130.0&amp;gt;: 14
iex(2)&amp;gt; r CountServer
{:reloaded, CountServer, [CountServer]}
iex(3)&amp;gt;
15:09:01.313 [error] GenServer #PID&amp;lt;0.130.0&amp;gt; terminating
** (FunctionClauseError) no function clause matching in CountServer.handle_info/2
    (odd) lib/count_server.ex:13: CountServer.handle_info(:increment, 14)
    (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:711: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: :increment
State: 14
** (EXIT from #PID&amp;lt;0.128.0&amp;gt;) shell process exited with reason: an exception was raised:
    ** (FunctionClauseError) no function clause matching in CountServer.handle_info/2
        (odd) lib/count_server.ex:13: CountServer.handle_info(:increment, 14)
        (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
        (stdlib) gen_server.erl:711: :gen_server.handle_msg/6
        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Interactive Elixir (1.7.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example results in a &lt;code&gt;FunctionClauseError&lt;/code&gt;, because the old version of the code passes &lt;code&gt;:increment&lt;/code&gt; as a message. Because we removed the clause that accepted it, the &lt;code&gt;CountServer&lt;/code&gt; crashes, as there&amp;#39;s no &lt;code&gt;handle_info/2&lt;/code&gt; to handle this case.&lt;/p&gt;
&lt;p&gt;Instead, we should have kept a clause that accepts the &lt;code&gt;:increment&lt;/code&gt; message so as to provide backward compatibility for the previous version to do a clean upgrade.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule CountServer do
  use GenServer

  # ...

  def handle_info(:increment, n) do
    handle_info({:increment, 2}, n)
  end

  def handle_info({:increment, value}, n) do
    incremented = n + value
    IO.puts(&amp;quot;- #{inspect(self())}: #{incremented}&amp;quot;)

    Process.send_after(self(), {:increment, 2}, 1000)

    {:noreply, incremented}
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;A First Look at Code Reloading&lt;/h2&gt;
&lt;p&gt;The logic required for hot code reloading is often already present but abstracted away. For instance, GenServers implement the &lt;code&gt;code_change/3&lt;/code&gt; callback with a stub that returns the unchanged state.&lt;/p&gt;
&lt;p&gt;In this episode, we made observations from the perspective of the module being upgraded. In a next episode, we&amp;#39;ll look at upgrading whole applications, production releases and Phoenix applications. Subscribe to &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;Elixir Alchemy&lt;/a&gt; to get the next episode delivered straight to your inbox.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How OTP Applications are structured</title>
    <link rel="alternate" href="https://blog.appsignal.com/2018/09/18/elixir-alchemy-how-otp-applications-are-structured.html"/>
    <id>https://blog.appsignal.com/2018/09/18/elixir-alchemy-how-otp-applications-are-structured.html</id>
    <published>2018-09-18T00:00:00+00:00</published>
    <updated>2018-09-18T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">OTP uses applications to package code into units or components. In this edition of Elixir Alchemy, we&#039;ll learn about how Elixir applications are used, configured and compiled.</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/erlang/otp&quot;&gt;OTP&lt;/a&gt;, the framework that provides standards to help build Erlang applications, uses &lt;em&gt;applications&lt;/em&gt; to package code into units or components. This convention helps structuring your code into logical groups of modules and a way to start and stop the application&amp;#39;s supervisors. Your Phoenix project is an application, but the Phoenix framework and Ecto are applications too.&lt;/p&gt;
&lt;p&gt;An application is a component that can be compiled by itself. It can depend on other applications, and it can take its own configuration. Unlike in other languages, this convention provides a standardized way to specify how the VM should interact with it.&lt;/p&gt;
&lt;p&gt;Aside from the compiled &lt;code&gt;.beam&lt;/code&gt; files containing virtual machine code, compiled applications consist of an &lt;em&gt;application specification&lt;/em&gt; &lt;code&gt;.app&lt;/code&gt; file that tells the VM how to handle the application, and an optional &lt;em&gt;application callback module&lt;/em&gt; that is used to start, run and stop the application.&lt;/p&gt;
&lt;h2&gt;Application Callback Modules&lt;/h2&gt;
&lt;p&gt;For applications with supervisors, the application callback module defines functions that start and stop the application. Applications without supervisors (usually libraries with functions you can call without no internal state) omit the callback module since the application doesn&amp;#39;t need to be started.&lt;/p&gt;
&lt;p&gt;In Elixir, an application callback module uses &lt;a href=&quot;https://hexdocs.pm/elixir/Application.html&quot;&gt;the &lt;code&gt;Application&lt;/code&gt; behavior&lt;/a&gt;. The behavior implements the &lt;code&gt;start/2&lt;/code&gt; and &lt;code&gt;stop/1&lt;/code&gt; callbacks. The former starts the application&amp;#39;s main supervisor, and the latter is an optional callback that&amp;#39;s used to clean up after stopping the supervisor.&lt;/p&gt;
&lt;p&gt;Elixir&amp;#39;s &lt;code&gt;mix new&lt;/code&gt; task automatically creates an application callback module when a new project is generated with the &lt;code&gt;--sup&lt;/code&gt; flag.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ mix new --sup elixir_app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated project contains an application callback module in &lt;code&gt;lib/elixir_app/application.ex&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ElixirApp.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      # Starts a worker by calling: ElixirApp.Worker.start_link(arg)
      # {ElixirApp.Worker, arg},
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: ElixirApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When used, the &lt;code&gt;Application&lt;/code&gt; module adds a &lt;a href=&quot;https://github.com/elixir-lang/elixir/blob/0429cdd95f10abe2f5b3d188c2c3574132cae474/lib/elixir/lib/application.ex#L328-L330&quot;&gt;stub of the &lt;code&gt;stop/1&lt;/code&gt; function&lt;/a&gt;, which returns an ok-tuple. The generated &lt;code&gt;start/2&lt;/code&gt; function starts the app&amp;#39;s main supervisor.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Application Specifications&lt;/h2&gt;
&lt;p&gt;Running &lt;code&gt;mix compile.app&lt;/code&gt; places the application&amp;#39;s specification in the &lt;code&gt;.app&lt;/code&gt; file in the &lt;code&gt;ebin&lt;/code&gt; directory, and is one of the steps taken when compiling the app with &lt;code&gt;mix compile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The specification contains Erlang terms which define the application. It lists the modules defined in the app, the version number and a list of other apps that the app depends on. It also specifies the module to be used as the callback that starts the app.&lt;/p&gt;
&lt;p&gt;The specification file is based on the settings in the application’s &lt;code&gt;mix.exs&lt;/code&gt; file. To be able to generate the specification, each app must have a name and version number defined in its project function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ElixirApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :elixir_app,
      version: &amp;quot;0.1.0&amp;quot;
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Below is a minimal sample &lt;code&gt;mix.exs&lt;/code&gt; file, which only lists the project name and version number, yields a specification that lists Elixir’s default applications and specifies the modules in the app.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;{application,elixir_app,
             [{applications,[kernel,stdlib,elixir]},
              {description,&amp;quot;elixir_app&amp;quot;},
              {modules,[&amp;#39;Elixir.ElixirApp&amp;#39;,&amp;#39;Elixir.ElixirApp.Application&amp;#39;]},
              {registered,[]},
              {vsn,&amp;quot;0.1.0&amp;quot;}]}.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Specifying and Configuring the Application Callback Module&lt;/h3&gt;
&lt;p&gt;Aside from the app&amp;#39;s name and version number, a &lt;code&gt;mix.exs&lt;/code&gt; file generated with the &lt;code&gt;--sup&lt;/code&gt; option has an &lt;code&gt;application&lt;/code&gt; function with a &lt;code&gt;mod&lt;/code&gt; key.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ElixirApp.MixProject do
  # ...

  def application do
    [
      mod: {ElixirApp.Application, []}
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When generating the specification, it includes the callback module. This key points to the application&amp;#39;s callback module, so the VM knows which module to use to start the application.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;{application,elixir_app,
             [{applications,[kernel,stdlib,elixir,logger]},
              {description,&amp;quot;elixir_app&amp;quot;},
              {modules,[&amp;#39;Elixir.ElixirApp&amp;#39;,&amp;#39;Elixir.ElixirApp.Application&amp;#39;]},
              {registered,[]},
              {vsn,&amp;quot;0.1.0&amp;quot;},
              {mod,{&amp;#39;Elixir.ElixirApp.Application&amp;#39;,[]}}]}.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Tip&lt;/em&gt;: The list in the &lt;code&gt;:mod&lt;/code&gt;-tuple is used to pass configuration options to the application. Anything passed in ends up as the arguments to the callback module&amp;#39;s &lt;code&gt;start/2&lt;/code&gt; function.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;:applications&lt;/code&gt; and &lt;code&gt;:extra_applications&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;applications&lt;/code&gt; key in the specification lists all the applications that your app depends on. By default, &lt;code&gt;mix compile.app&lt;/code&gt; includes &lt;code&gt;kernel&lt;/code&gt; &lt;code&gt;stdlib&lt;/code&gt; and &lt;code&gt;elixir&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ElixirApp.MixProject do
  use Mix.Project

  def project do
    [
      app: :elixir_app,
      version: &amp;quot;0.1.0&amp;quot;,
      deps: [{:appsignal, &amp;quot;~&amp;gt; 1.0.0&amp;quot;}]
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Dependencies are automatically added to the &lt;code&gt;applications&lt;/code&gt; list, and they’re automatically started before the application boots if they have an Application module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-erlang&quot;&gt;{application,elixir_app,
             [{applications,[kernel,stdlib,elixir,appsignal]},
              {description,&amp;quot;elixir_app&amp;quot;},
              {modules,[&amp;#39;Elixir.ElixirApp&amp;#39;,&amp;#39;Elixir.ElixirApp.Application&amp;#39;]},
              {registered,[]},
              {vsn,&amp;quot;0.1.0&amp;quot;}]}.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To add more applications like Elixir’s &lt;code&gt;logger&lt;/code&gt;, you add them to the &lt;code&gt;:extra_applications&lt;/code&gt; key and they will subsequently be added to the existing list.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule ElixirApp.MixProject do

  # ...

  def application do
    [
      extra_applications: [:logger],
      mod: {ElixirApp.Application, []}
    ]
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;:applications&lt;/code&gt; key is used to explicitly specify the applications that are to be included in the specification. When used, only the listed applications and the defaults will be added. Any other dependencies are not automatically included.&lt;/p&gt;
&lt;h2&gt;Applications all the way down&lt;/h2&gt;
&lt;p&gt;Each seperate library, as well as your application itself, is an application. Some applications have a supervision tree, requiring them to have a callback module that takes care of starting and stopping the whole application.&lt;/p&gt;
&lt;p&gt;Your application can depend on other applications, and each of these can have their own supervision trees and callback modules. Whatever&amp;#39;s in there, it&amp;#39;s always specified in the application specification file. Think of it as the formula for your Elixir. 😉&lt;/p&gt;
&lt;p&gt;This concludes our overview of OTP applications in Elixir. We&amp;#39;ve tried convey some of the beauty of one of OTP&amp;#39;s conventions. It is one of the many things we love about Elixir. If you do too, &lt;a href=&quot;https://twitter.com/appsignal&quot;&gt;let us know&lt;/a&gt; what you&amp;#39;d like to see us write about, or subscribe to the &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;Elixir Alchemy newsletter&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Lists vs Tuples in Elixirs</title>
    <link rel="alternate" href="https://blog.appsignal.com/2018/08/21/elixir-alchemy-list-vs-tuples.html"/>
    <id>https://blog.appsignal.com/2018/08/21/elixir-alchemy-list-vs-tuples.html</id>
    <published>2018-08-21T00:00:00+00:00</published>
    <updated>2018-08-21T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this episode of Elixir Alchemy, we’ll explore the use of Lists and Tuples in Elixir. We’ll take a look at how each of these data structures is used and see when it’s appropriate to use either one over the other.</summary>
    <content type="html">&lt;p&gt;Welcome to another edition of &lt;a href=&quot;/elixir-alchemy&quot;&gt;Elixir Alchemy&lt;/a&gt;. Today, we&amp;#39;ll explore the use of &lt;a href=&quot;https://hexdocs.pm/elixir/List.html&quot;&gt;Lists&lt;/a&gt; and &lt;a href=&quot;https://hexdocs.pm/elixir/Tuple.html&quot;&gt;Tuples&lt;/a&gt; in Elixir. We&amp;#39;ll take a look at how each of these data structures is used and see when it&amp;#39;s appropriate to use either one over the other.&lt;/p&gt;
&lt;h1&gt;Lists and Tuples in Elixir&lt;/h1&gt;
&lt;p&gt;Lists and Tuples share some similarities that can make it difficult to discern when each data structure is suitable for use. They can both hold several values of any type. Visually, they even look similar, the only difference is in the braces that each uses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; list = [1, 2, true, 3]
iex&amp;gt; tuple = {1, 2, true, 3}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, they have fundamental differences that are important when deciding which one to use to store your data.&lt;/p&gt;
&lt;p&gt;Lists are meant to hold variable-length data, and tuples are meant for single data points that have a fixed number of elements.&lt;/p&gt;
&lt;p&gt;Conceptually speaking, you can think of this as storing a sequence of numbers (a &lt;em&gt;list&lt;/em&gt; of numbers) versus storing several numbers corresponding to a certain value, for example, three numbers that correspond to a 3D point in space (i.e. a single value made up of 3 numbers).&lt;/p&gt;
&lt;h2&gt;Lists&lt;/h2&gt;
&lt;p&gt;Lists are represented internally as &lt;em&gt;linked lists&lt;/em&gt;. They have the following characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They support adding/removing elements&lt;/li&gt;
&lt;li&gt;Memory usage scales with the list size. The more elements the list has, the more memory it requires&lt;/li&gt;
&lt;li&gt;Fetching elements may sometimes be slow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Picture the list above (&lt;code&gt;[1, 2, true, 3]&lt;/code&gt;) laid out in your computer’s RAM. It is distributed arbitrarily, in no particular order, with each element holding a reference to the next one:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2018-08/list.png&quot; alt=&quot;List&quot;/&gt;&lt;/p&gt;
&lt;p&gt;In order to reach the 3rd element, the system needs to know where the list begins (which is pretty much all it knows), and then traverse from there. This means that to get to the 100th element, all 99 elements before it have to be traversed.&lt;/p&gt;
&lt;p&gt;To add a new element, a new memory slot is reserved &lt;strong&gt;anywhere where free memory is available&lt;/strong&gt;, and then a reference to it is added to the previous last element.&lt;/p&gt;
&lt;p&gt;Granted, there are optimizations that can be done by your compiler to optimize all of this. But the overall principle still holds.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h2&gt;Tuples&lt;/h2&gt;
&lt;p&gt;Tuples behave like static data structures, except that they don’t have explicit names for each element. Aside from that, all their other characteristics are pretty much the same:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They are meant to hold a fixed number of elements&lt;/li&gt;
&lt;li&gt;As a result of the previous point, memory usage is also static, and allocated upfront.&lt;/li&gt;
&lt;li&gt;The data structure does not support addition/removal of elements. Any change requires recreating an entirely new version of the structure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In memory, this looks a lot different from lists:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2018-08/tuple.png&quot; alt=&quot;Tuple&quot;/&gt;&lt;/p&gt;
&lt;p&gt;You can see that memory usage is a lot more predictable (it&amp;#39;s 100% predictable, actually).&lt;/p&gt;
&lt;p&gt;All that&amp;#39;s needed to access an element is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A reference to where the tuple’s memory begins&lt;/li&gt;
&lt;li&gt;The index of the element you’re accessing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Coming from other programming languages, you might recognize this as being very similar to accessing a static array. And you’d be right. Tuples are not much more than abstractions to statically-sized arrays. The difference comes in the semantic meaning given to both.&lt;/p&gt;
&lt;p&gt;Arrays tend to hold data we can append or remove from. And while old C-style arrays would often have a fixed size, more recent languages easily provide ways for us to push, pop, shift and unshift elements. The way memory is handled to support this varies from language to language.&lt;/p&gt;
&lt;p&gt;Tuples, on the other hand, are not meant to change. They provide one piece of information, not a list of pieces.&lt;/p&gt;
&lt;p&gt;Examples of items that would fit in a tuple:&lt;/p&gt;
&lt;h3&gt;Name &amp;amp; Email Pairs&lt;/h3&gt;
&lt;p&gt;You can see this represented in most email clients when you see &lt;code&gt;&amp;quot;Miguel Palhas &amp;lt;miguel@example.com&amp;gt;&amp;quot;&lt;/code&gt;. In Elixir, this could be &lt;code&gt;{&amp;quot;Miguel Palhas&amp;quot;, &amp;quot;miguel@example.com&amp;quot;}&lt;/code&gt;. There’s actually an &lt;a href=&quot;https://github.com/thoughtbot/bamboo&quot;&gt;Elixir library&lt;/a&gt; that does this.&lt;/p&gt;
&lt;h3&gt;2D Points&lt;/h3&gt;
&lt;p&gt;Such as &lt;code&gt;{ 1, 2 }&lt;/code&gt;. This could also be represented as a map &lt;code&gt;%{ x: 1, y: 2 }&lt;/code&gt;. Whichever you choose to use is mostly a matter of personal choice, and of the specific use-case.&lt;/p&gt;
&lt;h3&gt;Key-value Pairs&lt;/h3&gt;
&lt;p&gt;Any mapping between a key and a value can be a two-element tuple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;a = { :name, &amp;quot;Miguel Palhas&amp;quot; }
b = { :email, &amp;quot;miguel@example.com&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which leads us to an interesting point: Keyword lists. In Elixir, you may already have come across something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;list1 = [ name: &amp;quot;Miguel Palhas&amp;quot;, email: &amp;quot;miguel@example.com&amp;quot; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As it turns out, this is just syntactic sugar for a list, where each value is a 2-element tuple. It is equivalent to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;    list2 = [
      { :name, &amp;quot;Miguel Palhas&amp;quot;},
      { :email, &amp;quot;miguel@example.com&amp;quot; }
    ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can verify this yourself by fetching a single element from this list:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;    iex&amp;gt; Enum.at(list1, 0)
    {:name, &amp;quot;Miguel Palhas&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at how this would look like in memory, we’d see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/blog/2018-08/keyword.png&quot; alt=&quot;Keyword&quot;/&gt;&lt;/p&gt;
&lt;h2&gt;Can you Add to Tuples?&lt;/h2&gt;
&lt;p&gt;Yes, you can. In Elixir, you have access to functions such as &lt;code&gt;Tuple.append/1&lt;/code&gt;, &lt;code&gt;Tuple.insert_at/1&lt;/code&gt; or &lt;code&gt;Tuple.delete_at/1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Looking at what they do, you may be tempted to use them as you would with lists, adding and removing elements at-will.&lt;/p&gt;
&lt;p&gt;However, these functions are rarely used, since what they actually do is create an entirely new tuple with the updated result somewhere else in memory. As you can probably see, this doesn&amp;#39;t scale well. Constantly re-creating your tuple to add a few elements quickly gets out of hand.&lt;/p&gt;
&lt;p&gt;With a list, adding/removing elements is a cheap operation that doesn’t need to mess with existing memory, which is why they’re more suited for dynamic collections.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;We touched on the differences in data structure between Lists and Tuples. And got to the cool stuff about how this works out in memory. Tuples are cheaper to get data out of, Lists are cheaper to add to.&lt;/p&gt;
&lt;p&gt;We&amp;#39;d love to know what you thought of this article, or if you have any questions. We’re always on the lookout for topics to investigate and explain, so if there’s anything in Elixir you’d like to read about, don&amp;#39;t hesitate to let us know at &lt;a href=&quot;https://twitter.com/appsignal&quot;&gt;@AppSignal&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Parsing Numbers in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2018/07/24/elixir-alchemy-parsing-numbers-in-elixir.html"/>
    <id>https://blog.appsignal.com/2018/07/24/elixir-alchemy-parsing-numbers-in-elixir.html</id>
    <published>2018-07-24T00:00:00+00:00</published>
    <updated>2018-07-24T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In this episode of Elixir Alchemy, we&#039;ll see how parsing integers and floats from strings work in Elixir and other programming languages.</summary>
    <content type="html">&lt;p&gt;Like any modern programming language, Elixir has built-in tools for doing basic tasks, such as parsing numbers from strings. Although they&amp;#39;re built-in and ready to use, it&amp;#39;s useful to understand the underlying algorithms.&lt;/p&gt;
&lt;p&gt;In this post we&amp;#39;ll first explain how to convert strings to integers in Elixir. This will be quick and useful. After that we&amp;#39;ll go straight down the rabbit hole and explain the underlying algorithms. This is the Alchemy we love. It may help you implement a parser for something similar, but it will definitely satisfy your curiosity about the mathematical ideas behind parsing numbers in Elixir.&lt;/p&gt;
&lt;h2&gt;The Quick (and Boring) Built-in&lt;/h2&gt;
&lt;p&gt;In Elixir, you can convert strings to floating point numbers using &lt;code&gt;Float.parse/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Float.parse(&amp;quot;1.2&amp;quot;)
{1.2, &amp;quot;&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This returns a tuple, where the first element is the parsed number, and the second is whatever was left of your input string once a non-numeric character was found. This is useful if you’re unsure whether your input contains additional data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; Float.parse(&amp;quot;3 stroopwafels&amp;quot;)
{3.0, &amp;quot; stroopwafels&amp;quot;}

iex&amp;gt; Float.parse(&amp;quot;stroopwafels? 3, please&amp;quot;)
:error # This fails because the number needs to be at the beginning of the string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you’re sure your input is a well-formatted floating point number with no additional characters, you can use a more direct approach:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;iex&amp;gt; String.parse_float(&amp;quot;1.2&amp;quot;)
1.2

iex&amp;gt; String.parse_float(&amp;quot;3 stroopwafels&amp;quot;)
** (ArgumentError) argument error
    :erlang.binary_to_float(&amp;quot;3 stroopwafels&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To satisfy our technical curiosity, let&amp;#39;s dive in and see how this works internally. We won&amp;#39;t implement everything that&amp;#39;s required for reliably parsing floats and integers, but we&amp;#39;ll learn enough to understand the fundamentals.&lt;/p&gt;
&lt;h2&gt;Down the Rabbit Hole&lt;/h2&gt;
&lt;p&gt;One way of thinking about number parsing is by decomposing a number into multiple components:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;1234 = 1000 + 200 + 30 + 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this knowledge, we can use a divide-and-conquer strategy to parse the number, by parsing each of its digits individually. Elixir’s pattern matching and recursive capabilities also fit in nicely here.&lt;/p&gt;
&lt;h3&gt;Parsing a Single Digit&lt;/h3&gt;
&lt;p&gt;Let’s start with a single digit integer for demonstration purposes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Parser do
  def ascii_to_digit(ascii) when ascii &amp;gt;= 48 and ascii &amp;lt; 58 do
    ascii - 48
  end
  def ascii_to_digit(_), do: raise ArgumentError
end
&lt;/code&gt;&lt;/pre&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;p&gt;The &lt;code&gt;ascii_to_digit/1&lt;/code&gt; function expects the &lt;a href=&quot;https://en.wikipedia.org/wiki/ASCII&quot;&gt;ASCII&lt;/a&gt; code of a single digit and returns the corresponding integer. This should only work for actual numeric characters, which are in the 48 to 57 range of the ASCII table. Any other value will cause an exception to be raised.&lt;/p&gt;
&lt;p&gt;Knowing the fact that numerical digits are declared sequentially in the ASCII table, we can simply subtract 48 to get the actual numeric value. This function will be a useful helper in the next section.&lt;/p&gt;
&lt;h3&gt;Parsing an Entire Integer&lt;/h3&gt;
&lt;p&gt;Now let’s add a function to handle an entire string containing an integer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Parser do
  def parse_int(str) do
    str
    |&amp;gt; String.reverse()
    |&amp;gt; do_parse_int(0, [])
  end

  def do_parse_int(&amp;lt;&amp;lt;char :: utf8&amp;gt;&amp;gt; &amp;lt;&amp;gt; rest, index, cache) do
    new_part = ascii_to_digit(char) * round(:math.pow(10, index))

    do_parse_int(
      rest,
      index + 1,
      [new_part | cache]
    )
  end
  def do_parse_int(&amp;quot;&amp;quot;, _, cache) do
    cache
    |&amp;gt; Enum.reduce(0, &amp;amp;Kernel.+/2)
  end

  # ...
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the &lt;code&gt;do_parse_int/3&lt;/code&gt; function traverses the string, using two auxiliary arguments: a counter that increments with every new digit, giving us our current index in the traversal, and an array where we keep intermediary values.&lt;/p&gt;
&lt;p&gt;Also, notice that we’re first reversing the string. This is because Elixir’s pattern matching only allows us to match the beginning of a string, not the end. We want to start from the least significant digit, which is at the right end of a number. So we first reverse the string, then make the traversal from left-to-right.&lt;/p&gt;
&lt;p&gt;For each, digit, we’re multiplying it with &lt;code&gt;10^index&lt;/code&gt;. This means that for the string &lt;code&gt;&amp;quot;1234&amp;quot;&lt;/code&gt; we end up with the following array:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[1000, 200, 30, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All that&amp;#39;s left is to sum up all the elements, which is done once we match an empty string.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: An optimized version of this could run the &lt;code&gt;Enum.reduce&lt;/code&gt; call on the original characters of a string, summing the digits right away instead of keeping a temporary list. We didn&amp;#39;t do this here so that we could split the responsibilities a bit better and leave the code more readable.&lt;/p&gt;
&lt;h3&gt;Parsing Floats&lt;/h3&gt;
&lt;p&gt;To implement a &lt;code&gt;parse_float/1&lt;/code&gt; function, all that&amp;#39;s left is to handle decimals. Fortunately, we can reuse our existing &lt;code&gt;parse_int/1&lt;/code&gt; function, along with a couple of fancy tricks to make everything work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Parser do
  @float_regex ~r/^(?&amp;lt;int&amp;gt;\d+)(\.(?&amp;lt;dec&amp;gt;\d+))?$/

  def parse_float(str) do
    %{&amp;quot;int&amp;quot; =&amp;gt; int_str, &amp;quot;dec&amp;quot; =&amp;gt; decimal_str} = Regex.named_captures(@float_regex, str)

    decimal_length = String.length(decimal_str)

    parse_int(int_str) + parse_int(decimal_str) * :math.pow(10, -decimal_length)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We define a &lt;code&gt;@float_regex&lt;/code&gt; module variable, which holds a regular expression capable of capturing both the left and right side of a floating point number. The decimal separator, and it’s subsequent digits, are optional, so this regex will match &lt;code&gt;&amp;quot;123&amp;quot;&lt;/code&gt; just as well as it matches &lt;code&gt;&amp;quot;123.456&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Explaining the details of this regex is out of the scope of this article, but feel free to play around with it in your Elixir console.&lt;/p&gt;
&lt;p&gt;When we run the regex, against our input, say &lt;code&gt;&amp;quot;123.456&amp;quot;&lt;/code&gt;, we end up with the following map:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;%{
  &amp;quot;int&amp;quot; =&amp;gt; &amp;quot;123&amp;quot;
  &amp;quot;dec&amp;quot; =&amp;gt; &amp;quot;456&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can now see where &lt;code&gt;parse_int/1&lt;/code&gt; comes in handy. It can be used on both parts to get &lt;code&gt;123&lt;/code&gt; and &lt;code&gt;456&lt;/code&gt;, respectively. But how can we combine them to have the desired &lt;code&gt;123.456&lt;/code&gt; as a result?&lt;/p&gt;
&lt;p&gt;Again, math comes to our rescue. Multiplying the decimal part by &lt;code&gt;10^-3&lt;/code&gt;, where &lt;code&gt;3&lt;/code&gt; is the length, gives us &lt;code&gt;0.456&lt;/code&gt;, which we can them add to the integer part to get the final result.&lt;/p&gt;
&lt;p&gt;Our end result can parse integers and floats from strings.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule Parser do
  def parse_int(str) do
    str
    |&amp;gt; String.reverse()
    |&amp;gt; do_parse_int(0, [])
  end

  def do_parse_int(&amp;lt;&amp;lt;char::utf8&amp;gt;&amp;gt; &amp;lt;&amp;gt; rest, index, cache) do
    new_part = ascii_to_digit(char) * round(:math.pow(10, index))

    do_parse_int(
      rest,
      index + 1,
      [new_part | cache]
    )
  end
  def do_parse_int(&amp;quot;&amp;quot;, _, cache) do
    cache
    |&amp;gt; Enum.reduce(0, &amp;amp;Kernel.+/2)
  end

  @float_regex ~r/^(?&amp;lt;int&amp;gt;\d+)(\.(?&amp;lt;dec&amp;gt;\d+))?$/

  def parse_float(str) do
    %{&amp;quot;int&amp;quot; =&amp;gt; int_str, &amp;quot;dec&amp;quot; =&amp;gt; decimal_str} = Regex.named_captures(@float_regex, str)

    decimal_length = String.length(decimal_str)

    parse_int(int_str) + parse_int(decimal_str) * :math.pow(10, -decimal_length)
  end

  def ascii_to_digit(ascii) when ascii &amp;gt;= 48 and ascii &amp;lt; 58 do
    ascii - 48
  end
  def ascii_to_digit(_), do: raise(ArgumentError)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Unhandled Cases&lt;/h2&gt;
&lt;p&gt;This was a somewhat summarized demonstration of how a low-level number parser could work in Elixir. However, it does not cover every possible scenario one might want. Some things that weren&amp;#39;t covered are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for negative numbers&lt;/li&gt;
&lt;li&gt;Support for scientific notation (e.g. &lt;code&gt;1.23e7&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;More graceful error handling. If you’re building a parser for your own use-case, then error handling should also depend on what the use case is, as well as its conditions. Hence, it was not covered here.&lt;/li&gt;
&lt;li&gt;Handling more numerical systems. Did you notice we’re using &lt;code&gt;:math.pow(10,x)&lt;/code&gt; in a few places? Making that &lt;code&gt;10&lt;/code&gt; configurable should allow us to support binary, octal or hexadecimal strings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;#39;d love to know what you thought of this article, or if you have any questions. We’re always on the lookout for topics to investigate and explain, so if there’s anything in Elixir you’d like to read about, don&amp;#39;t hesitate to let us know at &lt;a href=&quot;https://twitter.com/appsignal&quot;&gt;@AppSignal&lt;/a&gt;!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Deconstructing Elixir&#039;s GenServers</title>
    <link rel="alternate" href="https://blog.appsignal.com/2018/06/12/elixir-alchemy-deconstructing-genservers.html"/>
    <id>https://blog.appsignal.com/2018/06/12/elixir-alchemy-deconstructing-genservers.html</id>
    <published>2018-06-12T00:00:00+00:00</published>
    <updated>2018-06-12T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">Elixir uses GenServers to keep state and run code asynchronously. But how does this work? In this episode of Elixir Alchemy, we&#039;ll deconstruct Elixir&#039;s GenServer module to see how it works under the hood.</summary>
    <content type="html">&lt;p&gt;Instead of using object instances like in object oriented languages, Elixir uses &lt;a href=&quot;https://elixir-lang.org/getting-started/mix-otp/genserver.html&quot;&gt;&lt;em&gt;GenServers&lt;/em&gt;&lt;/a&gt; (generic servers) to store state in separate processes. GenServers can keep state and run code asynchronously, which is useful for keeping data available without passing it from function to function.&lt;/p&gt;
&lt;p&gt;But how does this work? In this episode of Elixir Alchemy, we&amp;#39;ll deconstruct Elixir&amp;#39;s &lt;code&gt;GenServer&lt;/code&gt; module to see how it functions. We&amp;#39;ll learn how a GenServer communicates with other processes, and how it keeps track of its state by implementing part of its functionality ourselves.&lt;/p&gt;
&lt;h2&gt;A key-value store&lt;/h2&gt;
&lt;p&gt;Before we can dive under the hood of the &lt;code&gt;GenServer&lt;/code&gt; module, we&amp;#39;ll take it for a spin to build a &lt;em&gt;key-value store&lt;/em&gt; that can store and retrieve values by key.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule KeyValue do
  # 1
  def init(state \\ %{}) do
    {:ok, state}
  end

  # 2
  def handle_cast({:put, key, value}, state) do
    {:noreply, Map.put(state, key, value)}
  end

  # 3
  def handle_call({:get, key}, _from, state) do
    {:reply, Map.fetch!(state, key), state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example has three &lt;em&gt;callback functions&lt;/em&gt; to initialize the store, put new values in the store, and query values by key.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;init/1&lt;/code&gt; function takes a state or defaults to an empty map. The &lt;code&gt;GenServer&lt;/code&gt; API requires the state to be returned in an ok-tuple.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;handle_cast/2&lt;/code&gt; callback is used to &lt;em&gt;cast&lt;/em&gt; an asynchronous message to our server, without waiting for a response. This server responds to a cast with a message matching &lt;code&gt;{:put, key, value}&lt;/code&gt; and puts a new key in map that holds the state. It returns a &lt;code&gt;:noreply&lt;/code&gt;-tuple to indicate the function doesn&amp;#39;t return a response, with the updated state.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To make synchronous calls, the &lt;code&gt;handle_call/3&lt;/code&gt; callback is used. This example responds to &lt;em&gt;call&lt;/em&gt; with a message matching &lt;code&gt;{:get, key}&lt;/code&gt;, which finds the key in the state and returns it in a &lt;code&gt;:reply&lt;/code&gt;-tuple along with the state.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To try our key-value store, we use the &lt;code&gt;start/2&lt;/code&gt;, &lt;code&gt;cast/3&lt;/code&gt; and &lt;code&gt;call/2&lt;/code&gt; functions on &lt;code&gt;GenServer&lt;/code&gt;. Internally, these use the internal callbacks defined in the key-value store.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(1)&amp;gt; {:ok, pid} = GenServer.start(KeyValue, %{})
{:ok, #PID&amp;lt;0.113.0&amp;gt;}
iex(2)&amp;gt; GenServer.cast(pid, {:put, :foo, &amp;quot;bar&amp;quot;})
:ok
iex(3)&amp;gt; GenServer.call(pid, {:get, :foo})
{:ok, &amp;quot;bar&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We initialize a new store, which returns the &lt;em&gt;pid&lt;/em&gt; (Process ID) in an ok-tuple. The pid is used to refer to our store process later when calling &lt;code&gt;cast&lt;/code&gt; and &lt;code&gt;call&lt;/code&gt; to set and retrieve a value.&lt;/p&gt;
&lt;h3&gt;Convenience functions&lt;/h3&gt;
&lt;p&gt;Since having to call to our server through &lt;code&gt;GenServer&lt;/code&gt;&amp;#39;s functions gets tedious, they&amp;#39;re usually abstracted away by adding functions to the server.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule KeyValue do
  use GenServer

  def start do
    GenServer.start(KeyValue, %{})
  end

  def put(server, key, value) do
    GenServer.cast(server, {:put, key, value})
  end

  def get(server, key) do
    GenServer.call(server, {:get, key})
  end

  # Callbacks

  def init(state) do
    {:ok, state}
  end

  def handle_cast({:put, key, value}, state) do
    {:noreply, Map.put(state, key, value)}
  end

  def handle_call({:get, key}, _from, state) do
    {:reply, Map.fetch!(state, key), state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By adding the &lt;code&gt;start/0&lt;/code&gt;, &lt;code&gt;get/2&lt;/code&gt; and &lt;code&gt;put/3&lt;/code&gt; functions, we don&amp;#39;t have to worry about the server&amp;#39;s internal implementation when calling its API.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(2)&amp;gt; {:ok, pid} = KeyValue.start
{:ok, #PID&amp;lt;0.113.0&amp;gt;}
iex(3)&amp;gt; KeyValue.put(pid, :foo, &amp;quot;bar&amp;quot;)
:ok
iex(4)&amp;gt; KeyValue.get(pid, :foo)
&amp;quot;bar&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;GenServer internals&lt;/h2&gt;
&lt;p&gt;To understand how our key-value server works under the hood, we&amp;#39;ll dive into the &lt;code&gt;GenServer&lt;/code&gt; module. It relies on &lt;em&gt;message passing&lt;/em&gt; and &lt;em&gt;recursion&lt;/em&gt; for communication and keeping state.&lt;/p&gt;
&lt;Banner lang=&quot;elixir&quot; /&gt;

&lt;h3&gt;Message passing between processes&lt;/h3&gt;
&lt;p&gt;As we discussed when we talked about &lt;a href=&quot;/2017/05/18/elixir-alchemy-demystifying-processes-in-elixir.html&quot;&gt;processes in Elixir&lt;/a&gt;, processes communicate by sending messages to each other. Most message passing is abstracted away while working in Elixir, but you can send a message to another process by using the &lt;code&gt;send/2&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;send(pid, :hello)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function takes the recipient&amp;#39;s &lt;code&gt;pid&lt;/code&gt; and a message to send. Usually, the message is an atom or a tuple when multiple arguments need to be passed.&lt;/p&gt;
&lt;p&gt;In the other process, the recipient receives the message in its mailbox. It can react to incoming messages using the &lt;code&gt;receive&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;receive do
  :hello -&amp;gt;
    IO.puts &amp;quot;Hello there!&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using pattern matching, different actions can be taken for different messages. In &lt;code&gt;GenServer&lt;/code&gt;, tuples with the &lt;code&gt;:&amp;quot;$gen_call&amp;quot;&lt;/code&gt; and &lt;code&gt;:&amp;quot;$gen_cast&amp;quot;&lt;/code&gt; keys are used to query and update the internal state, for example.&lt;/p&gt;
&lt;p&gt;Message passing is the first ingredient needed to build a server. In a GenServer, messages are passed to a separate spawned process to update and query its state.&lt;/p&gt;
&lt;h3&gt;State through recursion&lt;/h3&gt;
&lt;p&gt;Besides accepting messages, the process spawned by a GenServer uses looping to keep track of its initial state.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;def loop(state) do
  receive do
    message -&amp;gt; loop(message)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, a default state is passed to the &lt;code&gt;loop/1&lt;/code&gt; function, which calls the &lt;code&gt;receive&lt;/code&gt; function to check for new messages in the mailbox. If there are none, it will block the process and wait for one to come in. When a message is received, the function calls itself with the received message as its new state. The state is updated and the process is back to waiting for messages to come in.&lt;/p&gt;
&lt;p&gt;GenServers have a loop method internally, which reads incoming messages and calls the corresponding callback functions. After that, it calls itself again with the updated state.&lt;/p&gt;
&lt;h2&gt;Implementing our own GenServer&lt;/h2&gt;
&lt;p&gt;Now that we understand how a GenServer functions, we can partially implement our own version of the &lt;code&gt;GenServer&lt;/code&gt; module to understand how message passing and recursive state works together to make our key-value store work.&lt;/p&gt;
&lt;p&gt;In Elixir itself, the &lt;code&gt;GenServer&lt;/code&gt; module is mostly a wrapper around Erlang&amp;#39;s tried and tested &lt;code&gt;gen_server&lt;/code&gt;. We&amp;#39;ll implement a version in Elixir that is a subset of the original.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyGenServer do
  # 1
  def start(module, state) do
    {:ok, state} = module.init(state)
    {:ok, spawn(__MODULE__, :loop, [state, module])}
  end

  # 2
  def loop(state, module) do
    state =
      receive do
        {:&amp;quot;$gen_cast&amp;quot;, from, message} -&amp;gt;
          {:noreply, state} = module.handle_cast(message, state)
          state

        {:&amp;quot;$gen_call&amp;quot;, {pid, reference} = from, message} -&amp;gt;
          {:reply, reply, state} = module.handle_call(message, from, state)
          send(pid, {reference, reply})
          state
      end

    loop(state, module)
  end

  # ...

end
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;start/2&lt;/code&gt; function starts the server process. It calls the &lt;code&gt;init/1&lt;/code&gt; function on the passed module to allow it to set initial state and then &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#spawn/3&quot;&gt;spawns&lt;/a&gt; a process that runs the &lt;code&gt;loop/2&lt;/code&gt; function with the &lt;code&gt;state&lt;/code&gt; and &lt;code&gt;module&lt;/code&gt; variables as its arguments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;loop/2&lt;/code&gt; function accepts incoming messages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;When a &lt;code&gt;:&amp;quot;$gen_cast&amp;quot;&lt;/code&gt;-message comes in, the &lt;code&gt;handle_cast/2&lt;/code&gt; function is called on the module passed to the &lt;code&gt;start/2&lt;/code&gt; function (which is &lt;code&gt;KeyValue&lt;/code&gt; in our example). It expects a &lt;code&gt;:noreply&lt;/code&gt;-tuple to be returned with the new state. The new state is then used to run the &lt;code&gt;loop/2&lt;/code&gt; function again to wait for more messages.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:&amp;quot;$gen_call&amp;quot;&lt;/code&gt;-messages call the &lt;code&gt;handle_call/3&lt;/code&gt; function. Here, a &lt;code&gt;:reply&lt;/code&gt;-tuple is expected, with the reply and the new state. The reply is then sent back to the process that sent the message. Then, like when handing casts, the updated state is used to call the &lt;code&gt;loop/2&lt;/code&gt; function again.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The server part of our custom GenServer is done. We can now start our key-value store with our custom GenServer. Because our custom GenServer&amp;#39;s API matches Elixir&amp;#39;s, we can use the built-in version to communicate with a key value store started with our custom GenServer.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex&amp;gt; {:ok, pid} = MyGenServer.start(KeyValue, %{})
{:ok, #PID&amp;lt;0.119.0&amp;gt;}
iex&amp;gt; GenServer.cast(pid, {:put, :foo, &amp;quot;bar&amp;quot;})
:ok
iex&amp;gt; GenServer.call(pid, {:get, :foo})
&amp;quot;bar&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To understand the &lt;code&gt;cast/2&lt;/code&gt; and &lt;code&gt;call/2&lt;/code&gt; functions, we&amp;#39;ll implement those on our GenServer as well.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyGenServer do
  # ...

  # 1
  def cast(pid, message) do
    send(pid, {:&amp;quot;$gen_cast&amp;quot;, {self(), nil}, message})
    :ok
  end

  # 2
  def call(pid, message) do
    send(pid, {:&amp;quot;$gen_call&amp;quot;, {self(), nil}, message})

    receive do
      {_, response} -&amp;gt; response
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;To cast a message to our server, we&amp;#39;ll send a message in the cast-format to our server and return an ok-atom.&lt;/li&gt;
&lt;li&gt;Since a call requires a response, we&amp;#39;ll wait for a message to be sent back using the &lt;code&gt;receive&lt;/code&gt; function and return that.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;iex&amp;gt; {:ok, pid} = MyGenServer.start(KeyValue, %{})
{:ok, #PID&amp;lt;0.119.0&amp;gt;}
iex&amp;gt; MyGenServer.cast(pid, {:put, :foo, &amp;quot;bar&amp;quot;})
:ok
iex&amp;gt; MyGenServer.call(pid, {:get, :foo})
&amp;quot;bar&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can use our implementation to start our key-value store and communicate with it without needing Elixir&amp;#39;s &lt;code&gt;GenServer&lt;/code&gt; module.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MyGenServer do
  def start(module, state) do
    {:ok, state} = module.init(state)
    {:ok, spawn(__MODULE__, :loop, [state, module])}
  end

  def loop(state, module) do
    state =
      receive do
        {:&amp;quot;$gen_cast&amp;quot;, from, message} -&amp;gt;
          {:noreply, state} = module.handle_cast(message, state)
          state

        {:&amp;quot;$gen_call&amp;quot;, {pid, reference} = from, message} -&amp;gt;
          {:reply, reply, state} = module.handle_call(message, from, state)
          send(pid, {reference, reply})
          state
      end

    loop(state, module)
  end

  def cast(pid, message) do
    send(pid, {:&amp;quot;$gen_cast&amp;quot;, {self(), nil}, message})
    :ok
  end

  def call(pid, message) do
    send(pid, {:&amp;quot;$gen_call&amp;quot;, {self(), nil}, message})

    receive do
      {_, response} -&amp;gt; response
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Using GenServers in Elixir&lt;/h2&gt;
&lt;p&gt;We can now switch the convenience funtions in our key-value store over to our own GenServer implementation to verify everything still works.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule KeyValue do
  def start do
    MyGenServer.start(KeyValue, %{})
  end

  def put(server, key, value) do
    MyGenServer.cast(server, {:put, key, value})
  end

  def get(server, key) do
    MyGenServer.call(server, {:get, key})
  end

  # Callbacks

  def init(state) do
    {:ok, state}
  end

  def handle_cast({:put, key, value}, state) do
    {:noreply, Map.put(state, key, value)}
  end

  def handle_call({:get, key}, _from, state) do
    {:reply, Map.fetch!(state, key), state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;iex&amp;gt; {:ok, pid} = KeyValue.start
{:ok, #PID&amp;lt;0.113.0&amp;gt;}
iex&amp;gt; KeyValue.put(pid, :foo, &amp;quot;bar&amp;quot;)
:ok
iex&amp;gt; KeyValue.get(pid, :foo)
&amp;quot;bar&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This concludes our dive into Elixir&amp;#39;s GenServer internals. Our example implements parts of what Elixir&amp;#39;s built-in &lt;code&gt;GenServer&lt;/code&gt; can do. Although our implementation only covers part of what &lt;code&gt;GenServer&lt;/code&gt; and &lt;code&gt;gen_server&lt;/code&gt; do in Elixir and Erlang, it gives a peek into how a GenServer works internally.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: Our own GenServer implementation functions, but &lt;em&gt;shouldn&amp;#39;t be used for anything but educational purposes&lt;/em&gt;. Our version doesn&amp;#39;t include any of the built-in version&amp;#39;s fault tolerance, and can&amp;#39;t handle message timeouts, for example. Instead, use Elixir&amp;#39;s built-in GenServer. It&amp;#39;s based on Erlang&amp;#39;s &lt;code&gt;gen_server&lt;/code&gt;, which has been used in production apps for decades and comes with everything you need.&lt;/p&gt;
&lt;p&gt;Did we clear up some confusion about Elixir&amp;#39;s GenServers? We&amp;#39;d love to know what you think of this article, so please don&amp;#39;t hesitate to &lt;a href=&quot;https://twitter.com/appsignal&quot;&gt;let us know&lt;/a&gt;. We&amp;#39;d also love to know if you have any Elixir subjects you&amp;#39;d like to know more about.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Supervisors:
Building fault-tolerant
Elixir applications
</title>
    <link rel="alternate" href="https://blog.appsignal.com/2017/08/10/elixir-alchemy-supervisors-building-fault-tolerant-elixir-applications.html"/>
    <id>https://blog.appsignal.com/2017/08/10/elixir-alchemy-supervisors-building-fault-tolerant-elixir-applications.html</id>
    <published>2017-08-10T00:00:00+00:00</published>
    <updated>2017-08-10T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the second edition of Elixir Alchemy, Gonzalo explains supervision in Elixir applications.</summary>
    <content type="html">&lt;p&gt;We briefly touched on supervision when we talked about processes in &lt;a href=&quot;/2017/05/18/elixir-alchemy-demystifying-processes-in-elixir.html&quot;&gt;the first edition of Elixir Alchemy&lt;/a&gt;. In this edition, we&amp;#39;ll take it a step further by explaining how supervision works in Elixir, and we&amp;#39;ll give you an introduction into building fault tolerant applications.&lt;/p&gt;
&lt;p&gt;A phrase you&amp;#39;ll likely run into when reading up on fault tolerance in Elixir and Erlang is &amp;quot;Let it crash&amp;quot;. Instead of preventing exceptions from happening, or catching them immediately when they occur, you&amp;#39;re usually advised not to do any defensive programming. That might sound counter-intuitive — how do crashing processes help with building fault tolerant applications? Supervisors are the answer.&lt;/p&gt;
&lt;div className=&quot;header ruby_magic&quot;&gt;
  &lt;h2&gt;Fault tolerance&lt;/h2&gt;

&lt;p&gt;
  Instead of taking down the whole system when one of its components fail, fault
  tolerant applications can recover from exceptions by restarting the affected
  parts while the rest of the system keeps running.
&lt;/p&gt;

&lt;p&gt;
  In Elixir, supervisors are tasked with restarting processes when they fail.
  Instead of trying to handle all possible exceptions within a process, the &quot;Let
  it crash&quot;-philosophy shifts the burden of recovering from such failures to the
  process&#039; supervisor.
&lt;/p&gt;

  &lt;p&gt;The supervisor makes sure the process is restarted if needed, bringing it back to its initial state, ready to accept new messages.&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Supervisors&lt;/h2&gt;
&lt;p&gt;To see how supervisors work, we&amp;#39;ll use a &lt;a href=&quot;https://hexdocs.pm/elixir/GenServer.html&quot;&gt;GenServer&lt;/a&gt; with some state. We&amp;#39;ll implement a cast to store a value, and a call to retrieve that value later.&lt;/p&gt;
&lt;p&gt;When started, our GenServer sets its initial state to &lt;code&gt;:empty&lt;/code&gt; and registers itself by the name &lt;code&gt;:cache&lt;/code&gt;, so we can refer to it later.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/cache.ex
defmodule Cache do
  use GenServer

  def start_link() do
    GenServer.start_link(__MODULE__, :empty, [name: :cache])
  end

  def handle_call(:get, _from, state) do
    {:reply, state, state}
  end

  def handle_cast({:save, new}, _state) do
    {:noreply, new}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s jump into &lt;a href=&quot;https://hexdocs.pm/iex/IEx.html&quot;&gt;IEx&lt;/a&gt; to supervise our GenServer. The Supervisor has to be started with a list of workers. In our case, we&amp;#39;ll use a single worker with the module name (&lt;code&gt;Cache&lt;/code&gt;), and an empty list of arguments (because &lt;code&gt;Cache.start_link/0&lt;/code&gt; doesn&amp;#39;t take any).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ iex -S mix
iex(1)&amp;gt; import Supervisor.Spec
Supervisor.Spec
iex(2)&amp;gt; {:ok, _pid} = Supervisor.start_link([worker(Cache, [])], strategy: :one_for_one)
{:ok, #PID&amp;lt;0.120.0&amp;gt;}
iex(3)&amp;gt; GenServer.call(:cache, :get)
:empty
iex(4)&amp;gt; GenServer.cast(:cache, {:save, :hola})
:ok
iex(5)&amp;gt; GenServer.call(:cache, :get)
:hola
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the process crashes, our supervisor will automatically restart it. Let&amp;#39;s try that by killing the process manually.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;...
iex(6)&amp;gt; pid = Process.whereis(:cache)
#PID&amp;lt;0.121.0&amp;gt;
iex(7)&amp;gt; Process.exit(pid, :kill)
true
iex(8)&amp;gt; GenServer.call(:cache, :get)
:empty
iex(9)&amp;gt; Process.whereis(:cache)
#PID&amp;lt;0.127.0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, the &lt;code&gt;:cache&lt;/code&gt; process was restarted by our supervisor immediately when it crashed, and getting its value revealed that it returned to its initial state (&lt;code&gt;:empty&lt;/code&gt;).&lt;/p&gt;
&lt;h2&gt;Dynamic Supervisor&lt;/h2&gt;
&lt;p&gt;In our first example, the process we supervised was built to run indefinitely. In some cases, however, you&amp;#39;d want your application to spawn processes when needed, and shut them down when their work is done.&lt;/p&gt;
&lt;p&gt;Imagine that we want to track football matches. When a match starts, we&amp;#39;ll start a process. We&amp;#39;ll send messages to that process to update the score, and this process will live until the match ends.&lt;/p&gt;
&lt;p&gt;To try this out, we&amp;#39;ll define another GenServer named &lt;code&gt;FootballMatchTracker&lt;/code&gt;, which we can use to store and fetch the current score for both teams.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/football_match_tracker.ex
defmodule FootballMatchTracker do
  def start_link([match_id: match_id]) do
    GenServer.start_link(__MODULE__, :ok, [name: match_id])
  end

  def new_event(match_id, event) do
    GenServer.cast(match_id, {:event, event})
  end

  def get_score(match_id) do
    GenServer.call(match_id, :get_score)
  end

  def init(:ok) do
    {:ok, %{home_score: 0, away_score: 0}}
  end

  def handle_call(:get_score, _from, state) do
    {:reply, state, state}
  end

  def handle_cast({:event, event}, state) do
    new_state =
      case event do
        &amp;quot;home_goal&amp;quot; -&amp;gt; %{state | home_score: state[:home_score] + 1}
        &amp;quot;away_goal&amp;quot; -&amp;gt; %{state | away_score: state[:away_score] + 1}
        &amp;quot;end&amp;quot; -&amp;gt; Supervisor.terminate_child(:football_match_supervisor, self())
      end
    {:noreply, new_state}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we&amp;#39;ll implement a supervisor for &lt;code&gt;FootballMatchTracker&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;# lib/football_match_supervisor.ex
defmodule FootballMatchSupervisor do
  use Supervisor

  def start_link do
    Supervisor.start_link(__MODULE__, [], [name: :football_match_supervisor])
  end

  def init([]) do
    children = [
      worker(FootballMatchTracker, [], restart: :transient)
    ]

    supervise(children, strategy: :simple_one_for_one)
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each &lt;code&gt;FootballMatchTracker&lt;/code&gt; will be registered with a match identifier that will be given to it through its initialization. Since the &lt;code&gt;Supervisor&lt;/code&gt; behaviour is a GenServer under the hood, we can use all its features like registering it using a name, like we did before. In this case, we&amp;#39;ll use &lt;code&gt;:football_match_supervisor&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s take our supervisor for a spin. We&amp;#39;ll start a child with a &lt;code&gt;:match_id&lt;/code&gt;, check the initial state, and add a home goal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ iex -S mix
iex(1)&amp;gt; FootballMatchSupervisor.start_link()
{:ok, #PID&amp;lt;0.119.0&amp;gt;}
iex(2)&amp;gt; Supervisor.start_child(:football_match_supervisor, [[match_id: :match_123]])
{:ok, #PID&amp;lt;0.121.0&amp;gt;}
iex(3)&amp;gt; FootballMatchTracker.get_score(:match_123)
%{away_score: 0, home_score: 0}
iex(4)&amp;gt; FootballMatchTracker.new_event(:match_123, &amp;quot;home_goal&amp;quot;)
:ok
iex(5)&amp;gt; FootballMatchTracker.get_score(:match_123)
%{away_score: 0, home_score: 1}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we send an unknown message (&lt;code&gt;&amp;quot;goal&amp;quot;&lt;/code&gt; is not implemented in our GenServer), we&amp;#39;ll get an exception, and the process will crash.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(6)&amp;gt; FootballMatchTracker.new_event(:match_123, &amp;quot;goal&amp;quot;)
:ok
13:13:44.658 [error] GenServer :match_123 terminating
** (UndefinedFunctionError) function FootballMatchTracker.terminate/2 is undefined or private
    (supervisors_example) FootballMatchTracker.terminate({{:case_clause, &amp;quot;goal&amp;quot;}, [{FootballMatchTracker, :handle_cast, 2, [file: &amp;#39;lib/football_match_tracker.ex&amp;#39;, line: 24]}, {:gen_server, :try_dispatch, 4, [file: &amp;#39;gen_server.erl&amp;#39;, line: 601]}, {:gen_server, :handle_msg, 5, [file: &amp;#39;gen_server.erl&amp;#39;, line: 667]}, {:proc_lib, :init_p_do_apply, 3, [file: &amp;#39;proc_lib.erl&amp;#39;, line: 247]}]}, %{away_score: 0, home_score: 1})
    (stdlib) gen_server.erl:629: :gen_server.try_terminate/3
    (stdlib) gen_server.erl:795: :gen_server.terminate/7
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:&amp;quot;$gen_cast&amp;quot;, {:event, &amp;quot;goal&amp;quot;}}
State: %{away_score: 0, home_score: 1}
iex(8)&amp;gt; Process.whereis(:match_123)
#PID&amp;lt;0.127.0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because we used the &lt;code&gt;:transient&lt;/code&gt; as the restart option, and &lt;code&gt;:simple_one_for_one&lt;/code&gt; as the &lt;a href=&quot;https://hexdocs.pm/elixir/Supervisor.html#module-strategies&quot;&gt;restart strategy&lt;/a&gt; for our supervisor, the supervisor&amp;#39;s children will only be restarted on abnormal termination, like the exception above. Like before, the process is restarted, which brings it back to its initial state.&lt;/p&gt;
&lt;p&gt;When we stop the process using the &lt;code&gt;&amp;quot;end&amp;quot;&lt;/code&gt;-message, the supervisor won&amp;#39;t restart it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(9)&amp;gt; FootballMatchTracker.new_event(:match_123, &amp;quot;end&amp;quot;)
:ok
iex(10)&amp;gt; Process.whereis(:match_123)
nil
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Inside the Supervisor&lt;/h2&gt;
&lt;p&gt;Now that we&amp;#39;ve seen some examples of how to use supervisors, let&amp;#39;s take it a step further, and try to figure out how they work internally.&lt;/p&gt;
&lt;p&gt;A supervisor is basically a GenServer with the capability of starting, supervising and restarting processes. The child processes are linked to the supervisor, meaning the supervisor receives an &lt;code&gt;:EXIT&lt;/code&gt; message whenever one of its children crash, which prompts it to restart it.&lt;/p&gt;
&lt;p&gt;So, if we want to implement our own supervisor, we need to start a linked process for each of its children. If one crashes, we&amp;#39;ll catch the &lt;code&gt;:EXIT&lt;/code&gt; message, and we&amp;#39;ll start it again.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule MySupervisor do
  use GenServer

  def start_link(args, opts) do
    GenServer.start_link(__MODULE__, args, opts)
  end

  def init([children: children]) do
    Process.flag(:trap_exit, true) # for handling EXIT messages
    state =
      Enum.map(children,
        fn child -&amp;gt;
          {:ok, pid} = child.start_link()
          {pid, child}
      end)
      |&amp;gt; Enum.into(%{})
    {:ok, state}
  end

  def handle_info({:EXIT, from, reason}, state) do
    IO.puts &amp;quot;Exit pid: #{inspect from} reason: #{inspect reason}&amp;quot;
    child = state[from]
    {:ok, pid} = child.start_link()
    {:noreply, Map.put(state, pid, child)}
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s try it with our &lt;code&gt;Cache&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ iex -S mix
iex(1)&amp;gt; MySupervisor.start_link([children: [Cache]], [])
{:ok, #PID&amp;lt;0.108.0&amp;gt;}
iex(2)&amp;gt; GenServer.cast(:cache, {:save, :hola})
:ok
iex(3)&amp;gt; Process.whereis(:cache)
#PID&amp;lt;0.109.0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we kill the process, like we did before, our custom supervisor will automatically restart it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iex(4)&amp;gt; :cache |&amp;gt; Process.whereis |&amp;gt; Process.exit(:kill)
Exit pid: #PID&amp;lt;0.109.0&amp;gt; reason: :killed
true
iex(5)&amp;gt; Process.whereis(:cache)
#PID&amp;lt;0.113.0&amp;gt;
iex(6)&amp;gt; GenServer.call(:cache, :get)
:empty
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Our supervisor receives a list of children modules through the &lt;code&gt;start_link/2&lt;/code&gt; function, which are started by the &lt;code&gt;init/0&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;By calling &lt;code&gt;Process.flag(:trap_exit, true)&lt;/code&gt;, we&amp;#39;ll make sure the supervisor doesn&amp;#39;t crash when one of its children do.&lt;/li&gt;
&lt;li&gt;Instead, the supervisor will receive an &lt;code&gt;:EXIT&lt;/code&gt; message. When that happens, our supervisor finds the child module from the state of the crashed process and starts it again in a new one.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By learning how to use the &lt;code&gt;Supervisor&lt;/code&gt; behaviour module, we learned quite a bit about building fault-tolerant applications in Elixir. Of course, there&amp;#39;s more to supervisors than we could cover in this article, and the different options (like restarting strategies) can be found in &lt;a href=&quot;https://hexdocs.pm/elixir/Supervisor.html&quot;&gt;the Elixir documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We’d love to know how you liked this article, if you have any questions about it, and what you’d like to read about next, so be sure to let us know at &lt;a href=&quot;https://twitter.com/appsignal&quot;&gt;@AppSignal&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Demystifying processes in Elixir</title>
    <link rel="alternate" href="https://blog.appsignal.com/2017/05/18/elixir-alchemy-demystifying-processes-in-elixir.html"/>
    <id>https://blog.appsignal.com/2017/05/18/elixir-alchemy-demystifying-processes-in-elixir.html</id>
    <published>2017-05-18T00:00:00+00:00</published>
    <updated>2017-05-18T00:00:00+00:00</updated>
    <author>Roy Tomeij</author>
    <summary type="html">In the first edition of Elixir Alchemy, we&#039;ll dive into processes in Elixir by deconstructing the Task module.</summary>
    <content type="html">&lt;p&gt;Welcome to the first edition of &lt;a href=&quot;https://blog.appsignal.com/elixir-alchemy&quot;&gt;Elixir Alchemy&lt;/a&gt;, an e-mail series about Elixir by your friends at &lt;a href=&quot;https://www.appsignal.com&quot;&gt;AppSignal&lt;/a&gt;. In this edition, we&amp;#39;ll learn how processes work in Elixir by deconstructing the &lt;code&gt;Task&lt;/code&gt; module. Along the way, we&amp;#39;ll learn what processes are, how they communicate, and how crashes are handled. Let&amp;#39;s dive right in!&lt;/p&gt;
&lt;h2&gt;The Task module&lt;/h2&gt;
&lt;p&gt;One of the abstractions Elixir provides around processes is the &lt;code&gt;Task&lt;/code&gt; module. It&amp;#39;s used to spawn a process that executes a single action, without communicating with other processes. It&amp;#39;s frequently used to turn a sequential program into a concurrent one by running multiple functions asynchronously.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;defmodule API do
  def random do
    time = :rand.uniform(1000)
    :timer.sleep(time)
    time
  end
end

IO.inspect [API.random, API.random, API.random]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, we have an API that returns random numbers under 1000. Its only deficiency is that the number that&amp;#39;s returned is also the number of milliseconds the call will take. For example, if the random number this API returns is 517, the function will sleep for half a second before returning the results. Unlucky as we are, we need three random numbers, so we&amp;#39;ll have to call the API three times. With each process potentially taking a second to return, this piece of code can take more than three seconds to run.&lt;/p&gt;
&lt;p&gt;We can make this code asynchronous by starting three Tasks, which will start three processes that will run their own API call concurrently. After they&amp;#39;ve all been started, we await their results and print them out all at once.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[
  Task.async(&amp;amp;API.random/0),
  Task.async(&amp;amp;API.random/0),
  Task.async(&amp;amp;API.random/0)
]
|&amp;gt; Enum.map(&amp;amp;Task.await/1)
|&amp;gt; IO.inspect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, the code will only take as long as the slowest call, instead of all of them combined.&lt;/p&gt;
&lt;p&gt;Although this is quite a simple example, there&amp;#39;s a lot going on that&amp;#39;s abstracted away by the &lt;code&gt;Task&lt;/code&gt; module. What&amp;#39;s going on under the hood? By knowing what happens after we call &lt;code&gt;Task.async/1&lt;/code&gt;, we can get a better understanding of processes in Elixir, and it&amp;#39;ll make code that uses the &lt;code&gt;Task&lt;/code&gt; module easier to debug when something goes wrong. To do that, we&amp;#39;ll have to go a little deeper to learn more about how processes work in Elixir, and therefore in Erlang.&lt;/p&gt;
&lt;h2&gt;Processes in Erlang&lt;/h2&gt;
&lt;p&gt;Erlang&amp;#39;s processes are managed in the VM instead of by the operating system, allowing them to be lightweight and really fast to spawn. Due to the lack of process pools and the low memory footprint, Erlang programs can spawn as many processes as needed. To handle all of these processes, Erlang starts one scheduler per core which schedules time for each of the processes in its run queue. Erlang will even take care of load balancing between your schedulers.&lt;/p&gt;
&lt;p&gt;To prevent transient bugs and the need for &lt;a href=&quot;https://en.wikipedia.org/wiki/Lock_(computer_science)&quot;&gt;locks&lt;/a&gt;, Erlang&amp;#39;s processes don&amp;#39;t share memory. They can only communicate with each other through message passing.&lt;/p&gt;
&lt;p&gt;To spawn a new process from the current one, Elixir provides the &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#spawn/1&quot;&gt;&lt;code&gt;spawn/1&lt;/code&gt; function&lt;/a&gt;, which takes a function as its only argument. The function we pass will run in a newly spawned process, after which it disappears again.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;spawn(&amp;amp;API.random/0) # =&amp;gt; #PID&amp;lt;0.82.0&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the function will run asynchronously in another process, we don&amp;#39;t immediately get the result back. Instead, we receive a process identifier, or &amp;quot;PID&amp;quot;. We can use that PID as an address to send messages to our new process.&lt;/p&gt;
&lt;h2&gt;Messaging&lt;/h2&gt;
&lt;p&gt;Elixir&amp;#39;s processes communicate with each other by sending messages to each other&amp;#39;s mailboxes. A process can send a message to any other process, as long as it has the PID of that process as an address to send the message to.&lt;/p&gt;
&lt;p&gt;To retrieve the result from a spawned process in the parent process, the spawned process needs to send it to another process. To send a message to a process, Elixir provides the &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#send/2&quot;&gt;&lt;code&gt;send/2&lt;/code&gt; function&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;send(self(), :hello)

IO.puts receive do
  :hello -&amp;gt; &amp;quot;Hello to you too!&amp;quot;
  unknown -&amp;gt; ~s(Received unknown message: &amp;quot;#{unknown}&amp;quot;)
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, we&amp;#39;re sending the message &lt;code&gt;:hello&lt;/code&gt; to the current process by using &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#self/0&quot;&gt;&lt;code&gt;self/0&lt;/code&gt;&lt;/a&gt; to get the current process&amp;#39;s PID. For a process to retrieve a message from its mailbox, Elixir provides &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1&quot;&gt;&lt;code&gt;receive/1&lt;/code&gt;&lt;/a&gt;, which matches messages from the mailbox to the given patterns. If one matches, the message is removed from the mailbox and the pattern&amp;#39;s block is executed. If none match, the message is placed back into the mailbox to be reviewed at a later time.&lt;/p&gt;
&lt;p&gt;To get the resulting value of a function run in another process, we need to send a message from the spawned process to the process that spawned it. A process doesn&amp;#39;t know which process started it, because processes are completely isolated from each other. If we want to send a message back to the &amp;quot;parent&amp;quot; process, we&amp;#39;ll have to pass its PID when spawning a process.&lt;/p&gt;
&lt;p&gt;Using the &amp;quot;parent&amp;quot; PID, the function that&amp;#39;s spawned in the new process can send its results back to the parent process using the &lt;code&gt;send/1&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;parent = self()

spawn(fn() -&amp;gt;
  send(parent, API.random())
end)

receive do
  random -&amp;gt; IO.puts &amp;quot;Received #{random}&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The parent process is then tasked with receiving the message and acting on it. It uses the &lt;code&gt;receive/1&lt;/code&gt; function to retrieve a message from its mailbox. This blocks the parent process, as it&amp;#39;s waiting for the result of the function we spawned.&lt;/p&gt;
&lt;p&gt;If a message comes in, the &lt;code&gt;receive/1&lt;/code&gt; function picks it up, and we&amp;#39;re able to pattern match on the message&amp;#39;s value. In this example, we&amp;#39;ll simply print it out after removing it from the mailbox.&lt;/p&gt;
&lt;h2&gt;Crashes and timeouts&lt;/h2&gt;
&lt;p&gt;When spawning a new process, one thing to keep in mind is that it might crash before it had the chance to send its message back to the parent process. In such cases, the example above would hang on the &lt;code&gt;receive/1&lt;/code&gt; block indefinitely, causing a &lt;a href=&quot;https://en.wikipedia.org/wiki/Deadlock&quot;&gt;deadlock&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A solution is to add a timeout to your receive blocks using the &lt;code&gt;after&lt;/code&gt; keyword. That way, the &lt;code&gt;after&lt;/code&gt; block is run after a specified amount of time has passed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;receive do
  random -&amp;gt; IO.puts &amp;quot;Received #{random}&amp;quot;
after
  500 -&amp;gt; IO.puts &amp;quot;No response received&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Although the &lt;code&gt;after&lt;/code&gt; block here will do its job, it&amp;#39;s most likely not the best fallback to use for processes dying.&lt;/p&gt;
&lt;p&gt;Most importantly, the spawned process might just be slow instead of dead. Depending on your application, it could be better to just wait until we get a result instead of giving up after half a second. For our example application, this won&amp;#39;t work because we know each call can take up to a second to complete.&lt;/p&gt;
&lt;p&gt;Also, if the spawned process dies, it will take half a second for the parent process to notice. Instead, it would be nice for the parent process to know immediately when one of its spawned processes dies.&lt;/p&gt;
&lt;h2&gt;Error handling with linked processes&lt;/h2&gt;
&lt;p&gt;A link is a relationship between two processes. When a process crashes, it takes down all processes linked to it. That might sound like a bad thing, but it actually makes a lot of sense. By linking two processes together, we state that they&amp;#39;re dependent on each other.&lt;/p&gt;
&lt;h2&gt;Process supervision and letting it crash&lt;/h2&gt;
&lt;p&gt;A supervisor is a process that keeps its child processes alive by restarting them when needed. Its children can be &amp;quot;regular&amp;quot; processes, or other supervisors. By nesting supervisors, a supervision tree can be built that allows parts of an application to crash and be restarted without affecting the rest of the system.&lt;/p&gt;
&lt;p&gt;&amp;quot;Regular&amp;quot; processes are usually implemented to crash when a situation occurs they can&amp;#39;t recover from, because their supervisors are tasked with restarting them when needed. That way, only a small part of the application restarts while the rest continues as normal. With supervised processes, a lot of defensive programming can be avoided by only implementing the working path through our applications and leaving the rest to crash.&lt;/p&gt;
&lt;p&gt;If we wouldn&amp;#39;t state this dependency, each of our processes needs to be able to function without the other processes being available. Instead of trying to cover that with a lot of defensive programming, we can use linking to have the processes crash as soon as possible when one of their dependencies dies.&lt;/p&gt;
&lt;p&gt;Instead of using the &lt;code&gt;spawn/1&lt;/code&gt; function, which creates a &amp;quot;normal&amp;quot; process, we&amp;#39;ll use &lt;a href=&quot;https://hexdocs.pm/elixir/Kernel.html#spawn_link/1&quot;&gt;&lt;code&gt;spawn_link/1&lt;/code&gt;&lt;/a&gt; to create one linked to the parent process. Now, when the spawned process crashes, it&amp;#39;ll take the parent process down as well instead of hanging, waiting for a message to come in.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;parent = self()

spawn_link(fn() -&amp;gt;
  raise(&amp;quot;The API is down!&amp;quot;)
end)

receive do
  random -&amp;gt; IO.puts &amp;quot;Received #{random}&amp;quot;
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above, the main process will crash before reaching the &lt;code&gt;receive/1&lt;/code&gt; block, as it&amp;#39;s linked to the process spawned with &lt;code&gt;spawn_link/1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;09:16:35.682 [error] Process #PID&amp;lt;0.82.0&amp;gt; raised an exception
** (RuntimeError) The API is down!
    :erlang.apply/2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The majority of processes in Elixir are spawned as linked processes. The exception to that is spawning a process where the &amp;quot;parent&amp;quot; process isn&amp;#39;t interested in its result, and whether or not it succeeded.&lt;/p&gt;
&lt;h2&gt;How Tasks run functions asynchronously&lt;/h2&gt;
&lt;p&gt;When programming Elixir, you&amp;#39;ll rarely need to spawn new processes using the &lt;code&gt;spawn/1&lt;/code&gt; and &lt;code&gt;spawn_link/1&lt;/code&gt; functions. Like we briefly touched on before, Elixir provides &lt;a href=&quot;https://hexdocs.pm/elixir/Task.html&quot;&gt;the &lt;code&gt;Task&lt;/code&gt; module&lt;/a&gt; that abstracts away the messaging and error handling you&amp;#39;d have to do to run a function asynchronously.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elixir&quot;&gt;[
  Task.async(&amp;amp;API.random/0),
  Task.async(&amp;amp;API.random/0),
  Task.async(&amp;amp;API.random/0)
]
|&amp;gt; Enum.map(&amp;amp;Task.await/1)
|&amp;gt; IO.inspect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;#39;s look at the API example again. We call &lt;code&gt;Task.async/1&lt;/code&gt; three times, which starts three processes to run &lt;code&gt;API.random/0&lt;/code&gt;, and returns a Task struct for each of them. Each of these structs includes the PID for the started process. That&amp;#39;s a lot like we&amp;#39;ve seen before when calling &lt;code&gt;spawn_link/1&lt;/code&gt; ourselves.&lt;/p&gt;
&lt;p&gt;Each call to &lt;code&gt;API.random/0&lt;/code&gt; can take up to a second, but since they&amp;#39;ve been started in three separate processes, the time it takes to fetch three random numbers is as long as it takes to get the slowest one.&lt;/p&gt;
&lt;p&gt;In the new process, &lt;code&gt;API.random/0&lt;/code&gt; gets executed and its result is sent to the parent process using a call to &lt;code&gt;send/1&lt;/code&gt;. In the parent process, &lt;code&gt;Task.await/1&lt;/code&gt; is called for each of the Tasks to get their results. Under the hood, that&amp;#39;s done with a &lt;code&gt;receive/1&lt;/code&gt; block to wait for the results of each of the spawned processes.&lt;/p&gt;
&lt;p&gt;Finally, if &lt;code&gt;Task.await/1&lt;/code&gt;&amp;#39;s &lt;code&gt;receive/1&lt;/code&gt; block receives a message, it&amp;#39;s returned. If it doesn&amp;#39;t, it&amp;#39;ll time out and send an exit signal to the parent process.&lt;/p&gt;
&lt;p&gt;If the spawned process crashes, it&amp;#39;ll send an exit signal to the parent process, because both processes are linked. Instead of trying to handle processes not being available, we&amp;#39;ll let it crash and have the supervisor restart the parent process.&lt;/p&gt;
&lt;h2&gt;The basics of concurrency in Elixir&lt;/h2&gt;
&lt;p&gt;By deconstructing the Task module, we&amp;#39;ve gained some insight into processes. We&amp;#39;ve learned how to spawn a process, send messages to it, and how to handle received messages in processes. With this, we understand the basics of concurrency in Elixir (and in Erlang, for that matter).&lt;/p&gt;
&lt;p&gt;Using these primitives, we can understand what happens when a Task is started, even though its messaging is abstracted away for our convenience.&lt;/p&gt;
&lt;p&gt;That concludes our dive into processes in Elixir. We&amp;#39;d love to know how you liked this article, if you have any questions about it, and what you&amp;#39;d like to read about next, so be sure to let us know at &lt;a href=&quot;https://twitter.com/appsignal&quot;&gt;@AppSignal&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  </feed>
