<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: bakenator</title>
    <description>The latest articles on DEV Community by bakenator (@bakenator).</description>
    <link>https://dev.to/bakenator</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F148378%2F850905d9-9341-46e3-a1c3-afde90df446a.png</url>
      <title>DEV Community: bakenator</title>
      <link>https://dev.to/bakenator</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bakenator"/>
    <language>en</language>
    <item>
      <title>Visualize NodeJS Errors in Real Time with Llama Logs</title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Wed, 26 Aug 2020 02:20:11 +0000</pubDate>
      <link>https://dev.to/bakenator/visualize-nodejs-errors-in-real-time-with-llama-logs-3c18</link>
      <guid>https://dev.to/bakenator/visualize-nodejs-errors-in-real-time-with-llama-logs-3c18</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rRfqTgDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hg0hby3cx9m5dhdvs8s5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rRfqTgDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hg0hby3cx9m5dhdvs8s5.gif" alt="Node Errors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What?
&lt;/h1&gt;

&lt;p&gt;Have you ever wondered what is going on inside your program?  Wanted a visual way to inspect its inner workings?&lt;/p&gt;

&lt;p&gt;The gif above shows an example of &lt;a href="https://llamalogs.com"&gt;Llama Logs&lt;/a&gt;.  It is a new tool I created to let you see the inner workings of your applications in real time. It is ready for you to start using in your app for free today!&lt;/p&gt;

&lt;p&gt;Below I will walk through an example of using Llama Logs to show and debug errors in a basic express app as they happen.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Setup
&lt;/h1&gt;

&lt;p&gt;I am going to write a basic express app that takes in a user's email through a url param and saves it to the database if the email is a llamalogs.com domain.&lt;/p&gt;

&lt;p&gt;The basic logic will look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;customerEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isDomainOk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;domainCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDomainOk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;saveEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;We received your email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now the doozy is that I am going to write some horrible code that errors if the user forgets to include the @domain part of their email.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// toLowerCase will fail if the [1] value is undefined!&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainIsOk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llamalogs.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;domainIsOk&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Visualizing with Llama Logs
&lt;/h1&gt;

&lt;p&gt;Llama Logs is incredibly simple to set up.  Once you sign up on llamalogs.com, all you need to do is install the client via npm and then start logging.  Llama Logs will automatically turn your logs into an interactive graph.&lt;/p&gt;

&lt;p&gt;So for example lets update the domainCheck method to the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainIsOk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llamalogs.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="nx"&gt;LlamaLogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Domain Check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;domainIsOk&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;LlamaLogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
      &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Domain Check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`input: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;; Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So we have added a logging case for both the success and failure outcomes.  Llama Logs will then use the names provided in the "sender", "receiver", and "isError" attributes to automatically visualize the activity in your app as a series of points moving between components.&lt;/p&gt;

&lt;p&gt;In the graph below we can see the result of running a few calls to the server with valid emails and ones that cause errors. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rRfqTgDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hg0hby3cx9m5dhdvs8s5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rRfqTgDG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hg0hby3cx9m5dhdvs8s5.gif" alt="Node Errors"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Debugging
&lt;/h1&gt;

&lt;p&gt;Even better than visualizing the activity in the graph, Llama Logs will let you get data from your errors in real time.&lt;/p&gt;

&lt;p&gt;Remember in the domainCheck method we attached this attribute to the Llama Log?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`input: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;; Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By using this message attribute, that means that when we hover on the red error point, it will show the message.  The image below comes shows me hovering on an error.  The request it represents had the email param == "jd", missing the email domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3QDx210q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eqdh1qqsb6fkfvm4qoc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3QDx210q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eqdh1qqsb6fkfvm4qoc6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By using Llama Logs to visualize errors in your system, you can identify the sources of bugs faster and easier than ever before!&lt;/p&gt;

&lt;h1&gt;
  
  
  More Info
&lt;/h1&gt;

&lt;p&gt;Please visit &lt;a href="https://llamalogs.com"&gt;LlamaLogs.com&lt;/a&gt; for more information if you are interested.  The app is free and ready to use today.  Please feel free to contact me at &lt;a href="mailto:andrew@llamalogs.com"&gt;andrew@llamalogs.com&lt;/a&gt; if you have any questions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Full Code
&lt;/h1&gt;

&lt;p&gt;This is such a small express app I think it is easiest to include all of the code within this blog post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LlamaLogs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;llamalogs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;LlamaLogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;accountKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_ACCOUNT_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;graphName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_GRAPH_NAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;LlamaLogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;customerEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isDomainOk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;domainCheck&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isDomainOk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;saveEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;We received your email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Example app listening at http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainCheck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;domainIsOk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;llamalogs.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

    &lt;span class="nx"&gt;LlamaLogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Domain Check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;domainIsOk&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;LlamaLogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
      &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Domain Check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`input: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;; Error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;customerEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// pretend we are saving to a database here&lt;/span&gt;
    &lt;span class="nx"&gt;LlamaLogs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Domain Check&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Database&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>node</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Visualize Your Elixir/Phoenix App with Llama Logs</title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Mon, 17 Aug 2020 01:03:06 +0000</pubDate>
      <link>https://dev.to/bakenator/visualize-your-elixir-phoenix-app-with-llama-logs-43nn</link>
      <guid>https://dev.to/bakenator/visualize-your-elixir-phoenix-app-with-llama-logs-43nn</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--svoJhHOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7jtxpzsxh1q8uaz31o0o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--svoJhHOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7jtxpzsxh1q8uaz31o0o.gif" alt="Llama Logs Graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  About
&lt;/h1&gt;

&lt;p&gt;Do you ever wonder what is going on inside your Phoenix application? Struggle to remember exactly how that data is processed? Llama Logs can bring an end to these problems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://llamalogs.com/docs/what"&gt;Llama Logs&lt;/a&gt; is a brand new app that can automatically create real time interactive graphs of the activity within your Phoenix application. Llama Logs also seamlessly works with JS, Go, and Python.  &lt;strong&gt;It is ready for you to start using in your application for free today!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Below I will show you how to add Llama Logs to an example Phoenix application and visualize whats going on in the server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Example App
&lt;/h1&gt;

&lt;p&gt;For this post, I will set up and use a new Phoenix API application. This is a very simple Phoenix app. It will have only one resource, Projects. Projects will have 3 attributes. The type attribute will either be "Internal" or "External".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="s2"&gt;"projects"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;
    &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:string&lt;/span&gt;

    &lt;span class="n"&gt;timestamps&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Adding Llama Logs
&lt;/h1&gt;

&lt;p&gt;Llama Logs is very simple to add to an application.  There is a full getting started guide here: &lt;a href="https://llamalogs.com/docs/getting-started"&gt;https://llamalogs.com/docs/getting-started&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once Llama Logs is initialized, just a few log statements need to be added to generate a real time visual graph.&lt;/p&gt;

&lt;p&gt;For this application I thought it would be cool to visualize the incoming traffic based on whether the projects were internal or external. This can be accomplished by adding Llama Log statements into the controller.&lt;/p&gt;

&lt;p&gt;Here is an example of the changes to the create function in the project_controller.ex file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"project"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;HelloProjects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;LlamaLogs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;receiver:&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="no"&gt;LlamaLogs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;receiver:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Create"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="no"&gt;LlamaLogs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;receiver:&lt;/span&gt; &lt;span class="s2"&gt;"Database"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

      &lt;span class="n"&gt;conn&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:created&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_resp_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:show&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"show.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;project:&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that the values used for sender and receiver are evaluated dynamically. This makes it possible to use one statement for multiple data paths.&lt;/p&gt;

&lt;h1&gt;
  
  
  Llama Logs Graph
&lt;/h1&gt;

&lt;p&gt;The Llama Logs client will automatically aggregate and send the data from those statements into the Llama Logs servers. Once there, a graph of the information is created in real time to show the ongoing activity in the server.&lt;/p&gt;

&lt;p&gt;The graph below shows the activity within the example project with users creating, viewing, and updating their project models.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--svoJhHOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7jtxpzsxh1q8uaz31o0o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--svoJhHOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7jtxpzsxh1q8uaz31o0o.gif" alt="Llama Logs Graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each component in the graph is auto generated based on the strings in your Llama Log statements.&lt;/p&gt;

&lt;p&gt;Each shape moving between components represents multiple events. This way, up to millions of events can be visualized simultaneously.  The key of what each shape represents is shown below.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZOYawyEk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/scunwuvi7mc3lcf5gr0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZOYawyEk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/scunwuvi7mc3lcf5gr0f.png" alt="Llama Logs Key"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Errors
&lt;/h1&gt;

&lt;p&gt;The key shows error logs as well.  This is a neat feature of Llama Logs that lets you dynamically catch and visualize errors in your Phoenix application.&lt;/p&gt;

&lt;p&gt;With these lines added to the example app, errors during the project creation call can be caught.  Note the &lt;code&gt;is_error&lt;/code&gt; field in the third statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="s2"&gt;"project"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;HelloProjects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; 
      &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
        &lt;span class="no"&gt;LlamaLogs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;receiver:&lt;/span&gt; &lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
        &lt;span class="no"&gt;LlamaLogs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;receiver:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Create"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="no"&gt;LlamaLogs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(%{&lt;/span&gt;&lt;span class="ss"&gt;sender:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;project_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;receiver:&lt;/span&gt; &lt;span class="s2"&gt;"Database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;is_error:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt; 
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;put_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:bad_request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"error.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;%{})&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I set the name field on a project to be unique, so errors can be triggered by creating a project with a pre existing name. &lt;br&gt;
 And then below we can see in real time the errors that I set up while creating external projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w39urING--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0nh7c1b3k8cwn7n53bzi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w39urING--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0nh7c1b3k8cwn7n53bzi.gif" alt="Llama Log Errors Graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;p&gt;All the code used for this example Phoenix app can be found in this repo:&lt;br&gt;
&lt;a href="https://github.com/llamalogs/PhonixBlogExample"&gt;https://github.com/llamalogs/PhonixBlogExample&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More information on Llama Logs and the Elixir/Phoenix developer guide can be found at:&lt;br&gt;
 &lt;a href="https://llamalogs.com/docs"&gt;https://llamalogs.com/docs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please reach out if you have any questions or need help getting Llama Logs set up in your Phoenix application.  I can be reached at &lt;a href="mailto:andrew@llamalogs.com"&gt;andrew@llamalogs.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
      <category>webdev</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Intro to OOP in Elixir </title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Wed, 01 May 2019 20:41:50 +0000</pubDate>
      <link>https://dev.to/bakenator/intro-to-oop-in-elixir-3c9i</link>
      <guid>https://dev.to/bakenator/intro-to-oop-in-elixir-3c9i</guid>
      <description>&lt;h1&gt;
  
  
  Who is This For?
&lt;/h1&gt;

&lt;p&gt;Like many others I came to the Elixir language through the Phoenix framework and then became interested in writing Elixir outside of Phoenix.  But with its immutability and lack of class methods, my biggest challenge was figuring out how to get anything done.  &lt;/p&gt;

&lt;p&gt;This post is meant to go over some of the big lessons I learned about how to transition my OOP programming knowledge into productive Elixir code.  Most of these points are very simple, they just need to "click" in your thinking.&lt;/p&gt;

&lt;h1&gt;
  
  
  Functions and Data are separate
&lt;/h1&gt;

&lt;p&gt;In most OOP languages you use instances of classes (objects) to do the work of our program.  Each instance has a self contained state and then functions that can do work by referencing that state.  For instance a simple Ruby class may look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@cust_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name_backwards&lt;/span&gt;
      &lt;span class="vi"&gt;@cust_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;person_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Ted'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;person_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name_backwards&lt;/span&gt;
&lt;span class="c1"&gt;# outputs "deT"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Elixir functions can not have any references to &lt;code&gt;this&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;, or any other instance variables.  So the way to do something similar in Elixir is by having a function take the data (instance) as the first parameter.  Here is the Ruby code above rewritten in Elixir.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Ted"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;name_backwards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name_backwards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the code above we can see that the data of a person instance is kept completely outside of the Person.Functions module.  When we want to use a function on the person instance, we pass it into a function that takes a person instance as the first parameter.  &lt;/p&gt;

&lt;p&gt;In practice a module would never be named &lt;code&gt;Person.Functions&lt;/code&gt; because by definition the module is not tied to a person instance.  The &lt;code&gt;name_backwards&lt;/code&gt; function could be used on any object with a name field.&lt;/p&gt;

&lt;h1&gt;
  
  
  Update by Replacement
&lt;/h1&gt;

&lt;p&gt;One of the most common things to do in OOP is to use an instance of an object to track some state.  For example in Ruby&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@person_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_year&lt;/span&gt;
      &lt;span class="vi"&gt;@person_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@person_age&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_age&lt;/span&gt;
      &lt;span class="vi"&gt;@person_age&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;person_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;person_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_year&lt;/span&gt;
&lt;span class="n"&gt;person_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_year&lt;/span&gt;
&lt;span class="n"&gt;person_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_age&lt;/span&gt;
&lt;span class="c1"&gt;# outputs 32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In Elixir all objects are immutable, so how on earth can we update a field of this person instance?  It can be done by making a new person instance and replacing the old one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;age:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;add_year&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;new_age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;age:&lt;/span&gt; &lt;span class="n"&gt;new_age&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_age&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_year&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_year&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_age&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So instead of changing the value of the field within the instance, we return a new instance in the line &lt;code&gt;%{age: new_age}&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Global Objects are stored in Processes
&lt;/h1&gt;

&lt;p&gt;I am not advocating for the use of global state, however I do think this idea is fundamentally important to learning the basics of Elixir.  Also this may be a contrived example, but I think it will show the challenge of translating OOP to Elixir.  &lt;/p&gt;

&lt;p&gt;I added a ticket class which dispenses tickets.  It keeps track as each ticket goes out so that each person gets a unique ticket.  Fairly simple in Ruby since we can use the static field &lt;code&gt;@@ticket_count&lt;/code&gt; to keep track of the tickets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tickets&lt;/span&gt;
  &lt;span class="vc"&gt;@@ticket_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_ticket&lt;/span&gt;
    &lt;span class="n"&gt;next_ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vc"&gt;@@ticket_count&lt;/span&gt;
    &lt;span class="vc"&gt;@@ticket_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vc"&gt;@@ticket_count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;next_ticket&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="vi"&gt;@ticket_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;

   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_ticket&lt;/span&gt;
    &lt;span class="vi"&gt;@ticket_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Tickets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_ticket&lt;/span&gt;
    &lt;span class="vi"&gt;@ticket_num&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;person_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;person_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_ticket&lt;/span&gt;
&lt;span class="c1"&gt;#outputs 1&lt;/span&gt;
&lt;span class="n"&gt;person_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;person_2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_ticket&lt;/span&gt;
&lt;span class="c1"&gt;#outputs 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So how would we keep track of the ticket counts in Elixir?  By using what is called a GenServer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Tickets&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_ticket_num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Tickets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_ticket_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="no"&gt;Tickets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_ticket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="no"&gt;Tickets&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:get_ticket&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:get_ticket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;curr_ticket_num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;curr_ticket_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;curr_ticket_num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;get_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;next_ticket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Tickets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_ticket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;ticket_num:&lt;/span&gt; &lt;span class="n"&gt;next_ticket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Tickets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;person_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;ticket_num:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;#output %{ticket_num: 1}&lt;/span&gt;
&lt;span class="n"&gt;person_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;%{&lt;/span&gt;&lt;span class="ss"&gt;ticket_num:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Functions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# %{ticket_num: 2}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now this is getting more advanced, but it is the real beauty of Elixir.  In the &lt;code&gt;start_link(1)&lt;/code&gt; function, what we did was start another process with an instance of a GenServer named Tickets with an initial value of 1.  &lt;/p&gt;

&lt;p&gt;GenServers can do a lot of things, but here we are using it to store the current ticket number.  Each time we call &lt;code&gt;get_ticket&lt;/code&gt; the code flows through to the response &lt;code&gt;{:reply, curr_ticket_num, curr_ticket_num + 1}&lt;/code&gt; which is an order to the GenServer basically formatted as &lt;code&gt;{command_to_genserver, response_value, new_state_value}&lt;/code&gt;.  Now any Elixir module can get a ticket just by calling the &lt;code&gt;Tickets.get_ticket&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;In most OOP languages, starting another process is a very high level task.  In fact a dev can go for years more or less only working in the main process.  In Elixir however working with other processes is a fundamental skill.&lt;/p&gt;

&lt;p&gt;If you want to learn more about GenServers I would highly recommend writing your own!  Here is a &lt;a href="https://medium.com/qixxit-development/build-your-own-genserver-in-49-lines-of-code-1a9db07b6f13"&gt;tutorial&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap Up
&lt;/h1&gt;

&lt;p&gt;These were the first few things that came to my mind when thinking back about the challenges of learning Elixir.  Hope one of them was helpful for you.&lt;/p&gt;

&lt;p&gt;Coding in Elixir is Fun!&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>computerscience</category>
      <category>ruby</category>
      <category>phoenix</category>
    </item>
    <item>
      <title>A Tour of Task Async and Await</title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Thu, 18 Apr 2019 02:16:50 +0000</pubDate>
      <link>https://dev.to/bakenator/a-tour-of-task-async-and-await-6ad</link>
      <guid>https://dev.to/bakenator/a-tour-of-task-async-and-await-6ad</guid>
      <description>&lt;p&gt;One great thing about Elixir is that the source code for all the language modules is easily examinable.  For a personal project I was recently considering using the Task module instead of a spawn, but then I asked myself... &lt;/p&gt;

&lt;h1&gt;
  
  
  How do Tasks Work?
&lt;/h1&gt;

&lt;p&gt;If you look at the documentation for the Task module in Hex Docs it says &lt;code&gt;the most common use case for tasks is to convert sequential code into concurrent code by computing a value asynchronously&lt;/code&gt;, then it provides the example below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;do_some_work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;do_some_other_work&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to understand how Tasks work we can dive into the Task source code for each of the two functions used above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Task.async
&lt;/h3&gt;

&lt;p&gt;First there is a call to Task.async.  Below is the source code for both definitions of the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:apply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]])&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;function_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;is_atom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;is_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;mfa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;function_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervised&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_owner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;get_callers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;:nomonitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mfa&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;pid:&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;ref:&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;owner:&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Task.async/1 is a catch all function that passes the param function to Task.async/3 with :erlang.apply.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;{:ok, pid} = Task.Supervised.start_link(get_owner(owner), get_callers(owner), :nomonitor, mfa)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In this line of Task.async/3 the current pid (&lt;code&gt;owner&lt;/code&gt;) and original param function (&lt;code&gt;mfa&lt;/code&gt;) is passed to the Task.Supervised as params to the &lt;code&gt;Task.Supervised.start_link&lt;/code&gt; function.  &lt;code&gt;start_link&lt;/code&gt; then spawns a new process and returns its pid.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;send(pid, {owner, ref})&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next a copy of the owner_pid (&lt;code&gt;owner&lt;/code&gt;) and a monitor reference (&lt;code&gt;ref&lt;/code&gt;) is sent to the new Task.Supervised process. These are what the Task.Supervised process will use to identify itself to Task.await when it finishes running the function.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;%Task{pid: pid, ref: ref, owner: owner}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally Task.async/3 returns a Task struct to be used in Task.await/2 for identification.&lt;/p&gt;

&lt;p&gt;Next lets take a look what was going on inside Task.Supervised that was spawned&lt;/p&gt;

&lt;h3&gt;
  
  
  Task.Supervised
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:proc_lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spawn_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;])}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;owner_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mfa&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;receive&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;owner_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;demonitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:flush&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;invoke_mfa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mfa&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;{:ok, :proc_lib.spawn_link(__MODULE__, :reply, [owner, callers, monitor, fun])}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Task.Supervised.start_link starts a new process and calls its own reply function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;receive do&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{^owner_pid, ref} -&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the lines copied above, we can see that the first thing reply does is to wait for the {owner, ref} tuple that was sent up in the Task.async function.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;send(owner_pid, {ref, invoke_mfa(owner, mfa)})&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After it is received Task.Supervised runs the original user provided function in &lt;code&gt;invoke_mfa(owner, mfa)&lt;/code&gt;.  &lt;code&gt;invoke_mfa&lt;/code&gt; basically uses &lt;code&gt;apply(module, fun, args)&lt;/code&gt; internally with additional error handling. &lt;/p&gt;

&lt;p&gt;The result of the original function is then sent back to the owner process (wherever we ran Task.async).  This message back to the owner process will be picked up by Task.await&lt;/p&gt;
&lt;h3&gt;
  
  
  Task.await
&lt;/h3&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;ref:&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;owner:&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;is_timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;receive&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;demonitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:flush&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;reply&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;def await(%Task{ref: ref, owner: owner} = task, timeout \\ 5000) when is_timeout(timeout) do&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Task.await takes a Task struct and pulls out the ref attribute.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;receive do&lt;/code&gt;&lt;br&gt;
&lt;code&gt;{^ref, reply} -&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The function then calls &lt;code&gt;receive&lt;/code&gt; and waits for any incoming messages.  Each message from Task.Supervised has a ref it uses as an id to identify itself to Task.await.  &lt;/p&gt;

&lt;p&gt;&lt;code&gt;reply&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the ref is a match, the result is returned.&lt;/p&gt;
&lt;h3&gt;
  
  
  Summary of Task.async/Task.await lifecycle
&lt;/h3&gt;

&lt;p&gt;The function &lt;code&gt;fn -&amp;gt; do_some_work() end&lt;/code&gt; was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Given to Task.async as a param&lt;/li&gt;
&lt;li&gt;Within Task.async, given to a new Task.supervised process as a param&lt;/li&gt;
&lt;li&gt;Run in the Task.supervised process&lt;/li&gt;
&lt;li&gt;The result was sent in a message from the Task.supervised process back to the original process &lt;/li&gt;
&lt;li&gt;The message from Task.Supervised is caught in Task.await and returned&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;
  
  
  Why Use a Ref for Identification?
&lt;/h1&gt;

&lt;p&gt;Task.Supervised processes identify themselves with a &lt;code&gt;ref&lt;/code&gt; which was initialized all the way back in the line &lt;code&gt;ref = Process.monitor(pid)&lt;/code&gt;.  Why does it do this when we already have a variable to identify a process, pid?&lt;/p&gt;

&lt;p&gt;To be honest I dug around and looked through the source for a while and could not find a specific reason to use ref as an identifier instead of the pid.  It has been set up this way since the start of the Elixir source code.  If anyone has insights on this, I would be interested to know.&lt;/p&gt;
&lt;h1&gt;
  
  
  Out of Order Tasks?
&lt;/h1&gt;

&lt;p&gt;From this inspection of Tasks I learned something very valuable about messages between processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Messages may not be processed in the order in which they are received!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the Task.await function there is no base case for the &lt;code&gt;receive&lt;/code&gt; pattern matching.  If the message ref does not match, then there is no match.  What happens in this case? An example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;task1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class="ss"&gt;:timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="mi"&gt;1&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;task2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we can see that Task 1 is going to stall for 10 seconds before it returns.  So Task 2 is going to finish and send its response before Task 1.  But Task 1 is the first to block waiting for its response.  What is the output?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Even though the messages with the function results were received in the order [task2, task1] everything still worked.&lt;/p&gt;

&lt;p&gt;This is because if &lt;code&gt;receive&lt;/code&gt; finds no match for the latest incoming message, it simply puts that message back in the queue and keeps on waiting.  Then each time a new message is received it checks again and keeps blocking until a match is found. &lt;/p&gt;

&lt;p&gt;This also means that if there are already matching messages in the queue, &lt;code&gt;receive&lt;/code&gt; does not need to wait at all.  It will check all the existing messages in the queue and move forward if one is found to match.  That happens in this case within &lt;code&gt;Task.await(task2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Hope you found this dive into the Task async/await functionality interesting.  &lt;/p&gt;

&lt;p&gt;Coding in Elixir is Fun!&lt;/p&gt;

&lt;p&gt;Source code for the Task files can be found here:&lt;br&gt;
&lt;a href="https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/task.ex"&gt;Task Module&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/task/supervised.ex"&gt;Task.Supervised Module&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>phoenix</category>
    </item>
    <item>
      <title>A Deep Dive into Mix</title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Thu, 11 Apr 2019 01:40:30 +0000</pubDate>
      <link>https://dev.to/bakenator/a-deep-dive-into-mix-5cno</link>
      <guid>https://dev.to/bakenator/a-deep-dive-into-mix-5cno</guid>
      <description>&lt;p&gt;This post started out its life as a short example of bubble sort in elixir.  But I encountered an interesting message when I tried to run my script with &lt;code&gt;mix run bubble.exs&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;Cannot&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="s2"&gt;"mix run"&lt;/span&gt; &lt;span class="n"&gt;without&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;please&lt;/span&gt; &lt;span class="n"&gt;ensure&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="no"&gt;Mix&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exs&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;no&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mix&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;exs&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case since the file is a true one page script with no dependencies, I could have run &lt;code&gt;elixir bubble.exs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But this error message caught my attention and led to some bigger questions.  How does this flag work? How does Mix work?&lt;/p&gt;

&lt;h1&gt;
  
  
  Mix Tasks
&lt;/h1&gt;

&lt;p&gt;In this example we are using &lt;code&gt;mix run&lt;/code&gt; so I thought I would try to track down the run command in the mix source code.  Mix is a sub application within the Elixir source code.  So I went to the Elixir repo and tried a search for &lt;code&gt;"def run"&lt;/code&gt;.&lt;br&gt;
Repo: &lt;a href="https://github.com/elixir-lang/elixir/tree/master/lib/mix/lib"&gt;https://github.com/elixir-lang/elixir/tree/master/lib/mix/lib&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After poking around for a while I got lucky and found the module Mix.Tasks.Run. It appears that the "run" command is a Task within Mix.  This fits with the high level overview of mix provided in the top level Mix module file.&lt;/p&gt;

&lt;p&gt;Basically each of the default commands that you can provide to Mix in the command line is a separate task.  Each task has a corresponding module with a "run" method that is called.&lt;/p&gt;
&lt;h1&gt;
  
  
  Tracing a Mix Command
&lt;/h1&gt;

&lt;p&gt;Now that we know Mix is passing our run command to the Mix.Tasks.Run module, lets dig in.&lt;/p&gt;

&lt;p&gt;The file starts with a catch all run method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="no"&gt;OptionParser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_head!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;aliases:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;r:&lt;/span&gt; &lt;span class="ss"&gt;:require&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;p:&lt;/span&gt; &lt;span class="ss"&gt;:parallel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;e:&lt;/span&gt; &lt;span class="ss"&gt;:eval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;c:&lt;/span&gt; &lt;span class="ss"&gt;:config&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;strict:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="ss"&gt;parallel:&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="kn"&gt;require&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:keep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;eval:&lt;/span&gt; &lt;span class="ss"&gt;:keep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;config:&lt;/span&gt; &lt;span class="ss"&gt;:keep&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;mix_exs:&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="ss"&gt;halt:&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="no"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval_string&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="no"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require_file&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;Keyword&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:halt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_halt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reenable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="ss"&gt;:ok&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This method parses the command line options and passes the parsed data to a run method with more parameters.  Interesting that the --no-halt option is handled at this level.&lt;/p&gt;

&lt;p&gt;Also deep in the OptionParser file, I found this line interesting.&lt;br&gt;
&lt;code&gt;defp tag_option("no-" &amp;lt;&amp;gt; option = original, config) do&lt;/code&gt;&lt;br&gt;
The &lt;code&gt;no-&lt;/code&gt; syntax is used as a switch for options.  I always assumed that &lt;code&gt;--halt&lt;/code&gt; and &lt;code&gt;--no-halt&lt;/code&gt; would just be identified as separate strings  &lt;/p&gt;

&lt;p&gt;Next up we have the run method with expanded parameters.&lt;br&gt;
&lt;code&gt;def run(args, opts, head, expr_evaluator, file_evaluator) do&lt;/code&gt;&lt;br&gt;
First it does some more processing of the command line args, then we reach this crucial code block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;cond&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Project&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"app.start"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="s2"&gt;"--no-mix-exs"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="ss"&gt;:ok&lt;/span&gt;

      &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;raise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="s2"&gt;"Cannot execute &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;mix run&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; without a Mix.Project, "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="s2"&gt;"please ensure you are running Mix in a directory with a mix.exs file "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="s2"&gt;"or pass the --no-mix-exs option"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here we can see exactly where the &lt;code&gt;--no-mix-exs&lt;/code&gt; option comes into play.  &lt;/p&gt;

&lt;p&gt;First it checks if we are in a normal Mix project directory with &lt;code&gt;Mix.Project.get()&lt;/code&gt;.  If that returns false it checks the args for &lt;code&gt;--no-mix-exs&lt;/code&gt;.  Finally it will throw the error we saw at the start.  Mystery Solved!&lt;/p&gt;

&lt;h1&gt;
  
  
  Going Deeper
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Mix.Project.get()
&lt;/h3&gt;

&lt;p&gt;It took me forever to track down how this thing works!  &lt;/p&gt;

&lt;p&gt;When the Mix app is first invoked the Mix.CLI module tries to compile the &lt;code&gt;mix.exs&lt;/code&gt; file in the current directory.  By default that file will have the line &lt;code&gt;use Mix.Project&lt;/code&gt;.  Once the file is compiled it runs this post compile hook in Mix.Project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__after_compile__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_binary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This hook pushes the env.module name onto an internal stack that is checked in the &lt;code&gt;Mix.Project.get()&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mix.Task.run("app.start", args)
&lt;/h3&gt;

&lt;p&gt;If a mix.exs file is available in the current directory, the run function moves onto the line &lt;code&gt;Mix.Task.run("app.start", args)&lt;/code&gt;.  This starts a new task, as you may guess the task is in the Mix.Tasks.App.Start module.&lt;/p&gt;

&lt;p&gt;This module starts in its run method and progresses down several functions until it reaches the line &lt;code&gt;case Application.start(app, type) do&lt;/code&gt; This passes the app down to the erlang call &lt;code&gt;:application.start(app, type)&lt;/code&gt; to start the app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Back to Mix.Tasks.Run.run
&lt;/h1&gt;

&lt;p&gt;After checking if we are in a project directory, this function still has a few more tricks up its sleeve.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;    &lt;span class="n"&gt;process_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expr_evaluator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;regular?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;file_evaluator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="no"&gt;Mix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;raise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"No such file: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I wanted to include this because I think it is especially neat.  If you run a command like &lt;code&gt;mix run -e "IO.inspect 123"&lt;/code&gt; Mix will run the inline code.  This happens in the &lt;code&gt;process_load&lt;/code&gt; function.  It checks to see if the -e or eval opts were provided and then uses the Code.eval_string/1 function to run the code on the fly.&lt;/p&gt;

&lt;p&gt;Finally Mix will run any individual file given in the command line using the &amp;amp;Code.require_file/1 function.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap Up
&lt;/h1&gt;

&lt;p&gt;Thanks for making it this far.  It was a challenge to track down exactly what was going on in the Mix app, but it was well worth the effort.  Mix is probably the most used Elixir app there is!&lt;/p&gt;

&lt;p&gt;Now that you know all about Mix Tasks, maybe you will be inspired to write your own?  &lt;a href="https://dev.to/drumusician/things-you-could-do-with-mix-2ni3"&gt;https://dev.to/drumusician/things-you-could-do-with-mix-2ni3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coding in Elixir is fun!&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>mix</category>
    </item>
    <item>
      <title>Web Monitor with Email Notifications in Elixir</title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Wed, 03 Apr 2019 20:15:08 +0000</pubDate>
      <link>https://dev.to/bakenator/web-monitor-with-email-notifications-in-elixir-2ml9</link>
      <guid>https://dev.to/bakenator/web-monitor-with-email-notifications-in-elixir-2ml9</guid>
      <description>&lt;h1&gt;
  
  
  Why Build This In Elixir?
&lt;/h1&gt;

&lt;p&gt;First and foremost this app is a tool to learn more about writing elixir code outside of Phoenix.&lt;/p&gt;

&lt;p&gt;But! Elixir is an excellent language for a website monitoring tool.  By using a supervisor and outside mailing service, we get a highly resiliant tool from only a few lines of code.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Monitor
&lt;/h1&gt;

&lt;p&gt;To check our website we will use a single function module that performs the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;checks the response from the website&lt;/li&gt;
&lt;li&gt;sends an email out depending on whether or not the response was ok&lt;/li&gt;
&lt;li&gt;waits 1 hr&lt;/li&gt;
&lt;li&gt;starts the function over&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also added a limit on the successful case so that emails are only sent once per day if the website is up.  However when the site is down, email notifications will go out every hour.&lt;/p&gt;

&lt;p&gt;One of the most interesting things to note is how we can recur the same function with a timer. In most other languages you would have to use a cron job to get a scheduled recurring function.  Elixir can due this thanks to the power of its tail call optimization.&lt;/p&gt;

&lt;p&gt;Here is the full code for the module&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;WebMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;SimpleMonitor&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# boilerplate to prepare for :httpc.request&lt;/span&gt;
    &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ensure_all_started&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:inets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ensure_all_started&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ssl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="s2"&gt;"Monitor Started"&lt;/span&gt;
    &lt;span class="c1"&gt;# Could use the Task module here, but spawn_link used for educational reasons&lt;/span&gt;
    &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spawn_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;WebMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;SimpleMonitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:check_site&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;check_site&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# make web request and set timeout to 10 seconds&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="ss"&gt;:httpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'https://bakerbaker.dev'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]},&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="ss"&gt;:timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="s1"&gt;'HTTP/1.1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'OK'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;_headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_body&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc_now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="c1"&gt;# send email for alive website &lt;/span&gt;
          &lt;span class="no"&gt;WebMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mailer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_good_email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
        &lt;span class="c1"&gt;# send email for down website&lt;/span&gt;
        &lt;span class="no"&gt;WebMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mailer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send_bad_email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;# sleep for 1 hr&lt;/span&gt;
    &lt;span class="ss"&gt;:timer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# run check function again&lt;/span&gt;
    &lt;span class="n"&gt;check_site&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# returning informational object to the supervisor&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;child_spec&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
     &lt;span class="p"&gt;%{&lt;/span&gt;
        &lt;span class="ss"&gt;id:&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;start:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are several places in this module where we could beef up our code.  One way would be to use a Genserver and submit recursive calls to the check_site function. I chose the explicit spawn_link here to provide an example of manually supervising an independent process.&lt;/p&gt;

&lt;p&gt;We could have also used a Task instead of spawn_link to get better debugging/error handling capabilities.&lt;/p&gt;

&lt;p&gt;Finally I used the :httpc module over HTTPoison as a chance to learn.  I was inspired by this blog post: &lt;a href="https://virviil.github.io/2018/04/06/elixir-do-you-have-http-requests-you-are-doing-them-wrong/"&gt;https://virviil.github.io/2018/04/06/elixir-do-you-have-http-requests-you-are-doing-them-wrong/&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Sending Emails
&lt;/h1&gt;

&lt;p&gt;In the SimpleMonitor code I use a Mailer module for sending the emails.  This module was made with the very easy to use MailGun lib at &lt;a href="https://github.com/chrismccord/mailgun"&gt;https://github.com/chrismccord/mailgun&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting it up requires creating a free mailgun account.  For free accounts you have to confirm each recipient, but since I am the only recipient this is not a problem.&lt;/p&gt;

&lt;p&gt;I followed the set up tutorial and used the default Mailer module in the library as a guide. Once simplified it ended up as this for my app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;WebMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Mailer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# the :web_monitor atom is specific to this app's name&lt;/span&gt;
  &lt;span class="nv"&gt;@config&lt;/span&gt; &lt;span class="ss"&gt;domain:&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:web_monitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:mailgun_domain&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="ss"&gt;key:&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:web_monitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:mailgun_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Mailgun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;@config&lt;/span&gt;

  &lt;span class="nv"&gt;@from&lt;/span&gt; &lt;span class="s2"&gt;"site_checker@bakerbaker.dev"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;send_good_email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;send_email&lt;/span&gt; &lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="s2"&gt;"andrew@bakerbaker.dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;from:&lt;/span&gt; &lt;span class="nv"&gt;@from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;subject:&lt;/span&gt; &lt;span class="s2"&gt;"Site is up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;html:&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;strong&amp;gt;The site is good!&amp;lt;/strong&amp;gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;send_bad_email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;send_email&lt;/span&gt; &lt;span class="ss"&gt;to:&lt;/span&gt; &lt;span class="s2"&gt;"andrew@bakerbaker.dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;from:&lt;/span&gt; &lt;span class="nv"&gt;@from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;subject:&lt;/span&gt; &lt;span class="s2"&gt;"Site is DOWN!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="ss"&gt;html:&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;strong&amp;gt;The site is DOWN!&amp;lt;/strong&amp;gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pretty much all of the work is done by the Mailgun library through macros.&lt;/p&gt;

&lt;h1&gt;
  
  
  Starting the App
&lt;/h1&gt;

&lt;p&gt;The SimpleMonitor needs to be added to the supervision tree so that it will be called when the app starts.  &lt;/p&gt;

&lt;p&gt;Here is the full Application code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;WebMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@moduledoc&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;

  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Application&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# List all child processes to be supervised&lt;/span&gt;
    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;WebMonitor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;SimpleMonitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

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



&lt;p&gt;Now we can run test the app with &lt;code&gt;iex -S mix&lt;/code&gt; or create a Release to run permanently on a server&lt;/p&gt;

&lt;h1&gt;
  
  
  Going Further
&lt;/h1&gt;

&lt;p&gt;I wanted to provide this app as an example for anyone looking to move from Phoenix to more manual control of an Elixir app.  With automated email and a timed function, this app could be used as a start for building many other notifier apps.  For example an application that checks a web API on a recurring schedule and emails the results.  &lt;/p&gt;

&lt;p&gt;Hope you enjoyed and learned something! Coding in Elixir is fun!&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Measuring Stack Size in Elixir   </title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Fri, 29 Mar 2019 21:19:16 +0000</pubDate>
      <link>https://dev.to/bakenator/measuring-stack-size-in-elixir-10b1</link>
      <guid>https://dev.to/bakenator/measuring-stack-size-in-elixir-10b1</guid>
      <description>&lt;h1&gt;
  
  
  Why Measure?
&lt;/h1&gt;

&lt;p&gt;There are many good articles written on tail call optimization in Elixir.  This is what allows Elixir to recursively call a function forever without overloading the stack.  &lt;/p&gt;

&lt;p&gt;Here is a list of some of them: &lt;a href="https://dev.to/search?q=elixir%20tail"&gt;https://dev.to/search?q=elixir%20tail&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While most of these articles say that Elixir optimizes the recursion, I wanted to see it with my own eyes.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Code
&lt;/h1&gt;

&lt;p&gt;Below is a minimum amount of code to see an optimized recursive function in action. It simply prints out information about the current process, then recurs with a new number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;recursiveFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;proc_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
    &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="n"&gt;proc_info&lt;/span&gt;
    &lt;span class="n"&gt;recursiveFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If the function is run in iex, it will print the process information very quickly in the terminal.  Within that information object it will list the current stack_size and heap_size.  Here is what I got on my machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;total_heap_size: 15143,
heap_size: 4185,
stack_size: 46,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What we can see is that even though it is calling the function over and over, the stack_size should remain exactly the same.  The heap_size will move around but it should not increase very much.&lt;/p&gt;

&lt;h1&gt;
  
  
  Non Optimized Example
&lt;/h1&gt;

&lt;p&gt;Here is some code that will not be automatically optimized since the recursive function call is not the last thing evaluated in the function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;nonOptimizedFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;\\&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;proc_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; 
    &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="n"&gt;proc_info&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;nonOptimizedFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When this is run the stack size increases by one for every iteration just like we expected. The heap_size will also grow quickly as each new iteration adds an int to the heap.&lt;/p&gt;

&lt;h1&gt;
  
  
  Will This Crash?
&lt;/h1&gt;

&lt;p&gt;What was most interesting about this non optimized code is how large the stack can get.  &lt;/p&gt;

&lt;p&gt;In JavaScript land the stack limit can be reached quite quickly.  &lt;/p&gt;

&lt;p&gt;Running the non optimized example on my Mac, I get to a stack_size of 100k within a minute and the process keeps on trucking!&lt;/p&gt;

&lt;p&gt;This is because by default there is no maximum stack size for an Elixir process.  It will keep on growing the stack and heap until the process runs out of memory.  By default an Elixir process is allowed however much memory it wants, all the way until it crashes the BEAM VM.&lt;/p&gt;

&lt;p&gt;If we wanted to stop this from happening, we can add the following line to our code&lt;br&gt;
&lt;code&gt;Process.flag(:max_heap_size, 100_000)&lt;/code&gt;&lt;br&gt;
This will kill the process once it has gobbled up too much memory for our liking, but before crashing our whole app.&lt;/p&gt;

&lt;p&gt;Thanks for reading! Coding in Elixir is Fun!&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Deploying Elixir and Docker in Docker</title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Tue, 26 Mar 2019 18:56:49 +0000</pubDate>
      <link>https://dev.to/bakenator/deploying-a-ci-system-in-elixir-2k55</link>
      <guid>https://dev.to/bakenator/deploying-a-ci-system-in-elixir-2k55</guid>
      <description>&lt;p&gt;Recently I have been building a CI (continuous integration) app in elixir.  &lt;/p&gt;

&lt;p&gt;Why would I do that when there are plenty of good SaaS options?  For Fun!&lt;/p&gt;

&lt;p&gt;Along the way I have found out about a few interesting things that I thought I could share.  This post will focus solely on &lt;strong&gt;Elixir Release&lt;/strong&gt; and &lt;strong&gt;Docker in Docker&lt;/strong&gt;.  I will post another article on the elixir app itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does the CI App Do?
&lt;/h2&gt;

&lt;p&gt;This is a simple CI application.  It waits for Github webhook notifications, downloads and tests the new code, then sends the results back to Github.&lt;/p&gt;

&lt;p&gt;Working with github is detailed here: &lt;a href="https://developer.github.com/v3/guides/building-a-ci-server/"&gt;https://developer.github.com/v3/guides/building-a-ci-server/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does it Work?
&lt;/h2&gt;

&lt;p&gt;Here is where things start getting tricky.  Because we want to isolate the code being tested, we will need to run the tests inside a docker container.&lt;/p&gt;

&lt;p&gt;But also for portability of the CI app, our elixir code will also need to be running in a docker container.&lt;/p&gt;

&lt;p&gt;This brings us to the ultimate mind bender: &lt;strong&gt;Docker in Docker!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lets jump right in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dockerizing an Elixir Application
&lt;/h2&gt;

&lt;p&gt;Best practice to send elixir apps off to production is to use the built in Erlang Releases concept.  For elixir apps, this can be easily done through the Distillery library. &lt;a href="https://elixirschool.com/en/lessons/libraries/distillery/"&gt;https://elixirschool.com/en/lessons/libraries/distillery/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One hiccup is that the release needs to be built on an operating system matching the operating system where it will be deployed.  Docker can come to the rescue here because it allows you to build your elixir releases inside of docker to guarantee the deployed OS is identical to the build OS.&lt;/p&gt;

&lt;p&gt;A good post on the subject is here: &lt;a href="https://medium.com/@pentacent/getting-started-with-elixir-docker-982e2a16213c"&gt;https://medium.com/@pentacent/getting-started-with-elixir-docker-982e2a16213c&lt;/a&gt;&lt;br&gt;
And the officially recommended Dockerfile example is here: &lt;a href="https://hexdocs.pm/distillery/guides/working_with_docker.html"&gt;https://hexdocs.pm/distillery/guides/working_with_docker.html&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Docker in Elixir in Docker
&lt;/h2&gt;

&lt;p&gt;Remember, we want the OS with our elixir app to include docker so that we can launch containers for testing.  The guides above show how to build an elixir release in docker, but not with the OS needed for docker in docker.&lt;/p&gt;

&lt;p&gt;That OS is called "Docker in Docker"!  &lt;/p&gt;

&lt;p&gt;The official image is &lt;code&gt;docker:dind&lt;/code&gt;, but there are several variants on dockerhub.  We will be using a specific version &lt;code&gt;docker:18.09.0-dind&lt;/code&gt; so that we are sure it matches the &lt;code&gt;elixir:1.7.2-alpine&lt;/code&gt; OS used to build the release&lt;/p&gt;

&lt;p&gt;From the hexdocs.pm example, make a new Dockerfile and change the line&lt;br&gt;
&lt;code&gt;FROM alpine:${ALPINE_VERSION}&lt;/code&gt;&lt;br&gt;
to&lt;br&gt;
&lt;code&gt;FROM docker:18.09.0-dind&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Dockerfile CMD Bug
&lt;/h3&gt;

&lt;p&gt;Through trial and error I found that the line &lt;br&gt;
&lt;code&gt;CMD trap 'exit' INT; /opt/app/bin/${APP_NAME} foreground&lt;/code&gt;&lt;br&gt;
was overriding the CMD from the &lt;code&gt;docker:18.09.0-dind&lt;/code&gt; image.&lt;br&gt;
This results in the docker daemon not starting, which makes the image useless.&lt;/p&gt;

&lt;p&gt;To fix this I tracked down what the &lt;code&gt;docker:18.09.0-dind&lt;/code&gt; CMD is and put it in a shell script.&lt;/p&gt;

&lt;p&gt;So in the top level project directory add the following file &lt;code&gt;start.sh&lt;/code&gt;&lt;br&gt;
The sleep command is there to allow the docker daemon to start up before the elixir app starts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
dockerd-entrypoint.sh &amp;amp; 
&lt;span class="nb"&gt;sleep &lt;/span&gt;10
/opt/app/bin/ci foreground
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then update the end of the DockerFile to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./start.sh .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"chmod"&lt;/span&gt;, &lt;span class="s2"&gt;"+x"&lt;/span&gt;, &lt;span class="s2"&gt;"start.sh"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; /start.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Inner Docker Image
&lt;/h2&gt;

&lt;p&gt;We've sorted out the container that runs the elixir app on a &lt;code&gt;docker:dind&lt;/code&gt; image.  Now lets prepare the docker image that the tests will use to run.&lt;/p&gt;

&lt;p&gt;Create a folder at &lt;code&gt;test_runner&lt;/code&gt;&lt;br&gt;
Within this folder my Dockerfile looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:11.12.0-alpine&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk upgrade &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apk add &lt;span class="nt"&gt;--no-cache&lt;/span&gt; bash git openssh
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"chmod"&lt;/span&gt;, &lt;span class="s2"&gt;"+x"&lt;/span&gt;, &lt;span class="s2"&gt;"start.sh"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; /start.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and the &lt;code&gt;start.sh&lt;/code&gt; file looks like this (with personal details replaced)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &lt;span class="nt"&gt;-b&lt;/span&gt; branch_name https://&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;@github.com/&lt;span class="nv"&gt;$USER_NAME&lt;/span&gt;/&lt;span class="nv"&gt;$PROJECT&lt;/span&gt;.git
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_NAME&lt;/span&gt;
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Your inner docker image can be whatever you want.  And note it doesn't need any special &lt;code&gt;docker:dind&lt;/code&gt; OS to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the Image into Your App
&lt;/h2&gt;

&lt;p&gt;So we've made the testing image, but now we need the elixir app to have access to it inside the &lt;code&gt;docker:dind&lt;/code&gt; system.&lt;/p&gt;

&lt;p&gt;We can do this using the &lt;code&gt;docker save&lt;/code&gt; and &lt;code&gt;docker load&lt;/code&gt; commands.  These allow us to save a docker image to a file and then load it back up.&lt;/p&gt;

&lt;p&gt;If we run &lt;code&gt;docker save test_runner &amp;gt; test_runner.tar&lt;/code&gt; in the test_runner folder, we will get a new test_runner.tar file.&lt;/p&gt;

&lt;p&gt;Then in our main ./Dockerfile we can add the line (right before ENTRYPOINT)&lt;br&gt;
&lt;code&gt;COPY ./test_runner/test_runner.tar .&lt;/code&gt;&lt;br&gt;
This brings the file into our Elixir image.&lt;/p&gt;

&lt;p&gt;Finally we add this line to the main ./start.sh file&lt;br&gt;
&lt;code&gt;docker load &amp;lt; ./test_runner.tar&lt;/code&gt;&lt;br&gt;
This adds the image to our docker application so that is can be fired up from the elixir app.&lt;/p&gt;

&lt;p&gt;The final &lt;code&gt;./start.sh&lt;/code&gt; file should look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
dockerd-entrypoint.sh &amp;amp; 
&lt;span class="nb"&gt;sleep &lt;/span&gt;10
docker load &amp;lt; ./test_runner.tar
/opt/app/bin/ci foreground
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Starting a Container in Elixir
&lt;/h2&gt;

&lt;p&gt;Now that we have set up all the infrastructure for our apps, we are ready to use the container in the elixir app.&lt;/p&gt;

&lt;p&gt;Wherever it is needed you can use &lt;br&gt;
&lt;code&gt;System.cmd("docker", ["run", "test_runner"])&lt;/code&gt;&lt;br&gt;
That will run the docker image and return you the output and exit status in a tuple.&lt;/p&gt;

&lt;p&gt;Don't forget that we can tailor the test runner on the fly by passing in environment variables as well.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thank you if you've made it this far. No one said docker in docker would be easy!&lt;/p&gt;

&lt;p&gt;I realize that elixir deployment methods can be contentious, and docker in docker even more so.  I welcome any comments on alternative/better systems we could use here instead.&lt;/p&gt;

&lt;p&gt;Now here is a build script I wrote to automate all of the build steps after you set up your elixir project, Dockerfiles, and start.sh scripts.&lt;/p&gt;

&lt;p&gt;Final note, you must use the --privileged flag to make use of docker in docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;test_runner
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; test_runner &lt;span class="nb"&gt;.&lt;/span&gt;
docker save test_runner &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test_runner.tar
docker image &lt;span class="nb"&gt;rm &lt;/span&gt;test_runner
&lt;span class="nb"&gt;cd&lt;/span&gt; ../
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; elixir_app &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nb"&gt;rm &lt;/span&gt;test_runner/test_runner.tar
docker run &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$OUTER_PORT&lt;/span&gt;:&lt;span class="nv"&gt;$INNER_PORT&lt;/span&gt; &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; elixir_app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>docker</category>
    </item>
    <item>
      <title>Supervisor Intensity, what is it?</title>
      <dc:creator>bakenator</dc:creator>
      <pubDate>Fri, 22 Mar 2019 22:01:58 +0000</pubDate>
      <link>https://dev.to/bakenator/supervisor-intensity-what-is-it-47g2</link>
      <guid>https://dev.to/bakenator/supervisor-intensity-what-is-it-47g2</guid>
      <description>&lt;p&gt;Did you know that Elixir Supervisors will stop trying to restart a child process if  they detect something has gone haywire in the child?&lt;/p&gt;

&lt;p&gt;They do! &lt;/p&gt;

&lt;p&gt;This leads to the next question, how do they know when a child process is a lost cause? &lt;/p&gt;

&lt;p&gt;Supervisor Intensity!&lt;/p&gt;

&lt;h1&gt;
  
  
  What is it?
&lt;/h1&gt;

&lt;p&gt;The intensity setting of a Supervisor is how many failures it can tolerate from a child process within a certain period of time.  If more failures are recorded, then the Supervisor stops all child processes and fails itself.&lt;/p&gt;

&lt;p&gt;The intensity and period are optional settings that can be set in Elixir like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;max_restarts:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;max_seconds:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note that I have used the values that Elixir currently defaults to, 3 failures over a 5 second period.&lt;/p&gt;

&lt;h1&gt;
  
  
  When Do You Run Into This?
&lt;/h1&gt;

&lt;p&gt;I figured this out when stepping through a nice bug.  At the top of one of my child processes I had this line&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dispatch:&lt;/span&gt; &lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:gen_tcp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;active:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;packet:&lt;/span&gt; &lt;span class="ss"&gt;:http_bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;reuseaddr:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I was crashing the process on purpose and subsequently the entire app would shutdown.  This confused me, because shouldn't the Supervisor restart the process?&lt;br&gt;
This issue was that &lt;code&gt;:gen_tcp.listen&lt;/code&gt; returns an error if the port is already in use by another socket.  &lt;/p&gt;

&lt;p&gt;So after the first time, this module throws an error on the first line of &lt;code&gt;start_link&lt;/code&gt;.  The Supervisor very quickly tries and fails three times on that same bug and the Supervisor is shut down.&lt;/p&gt;
&lt;h1&gt;
  
  
  Why Do Supervisors Do This?
&lt;/h1&gt;

&lt;p&gt;In short it is to prevent infinite loops of processes trying to be restarted over and over.  &lt;/p&gt;

&lt;p&gt;However note that the Supervisor does not just stop trying to restart the child.  If the intensity limits are surpassed the Supervisor shuts down itself.  &lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;It shuts down so that any possible Supervisor of that Supervisor can be notified that something wacky is going on and try to fix the issue.  The original Supervisor already gave it its best effort and is now basically passing the issue up a level to ask for help.&lt;/p&gt;
&lt;h1&gt;
  
  
  Try at Home!
&lt;/h1&gt;

&lt;p&gt;Here is a nice little module you can try out in your own app.&lt;br&gt;&lt;br&gt;
Drop this line into your Supervisor child start list&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;FailTwoSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And add this module to your project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;FailTwoSeconds&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt; &lt;span class="s2"&gt;"New Process Starting"&lt;/span&gt;

        &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spawn_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
            &lt;span class="no"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Failing Now"&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;child_spec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="p"&gt;%{&lt;/span&gt;
            &lt;span class="ss"&gt;id:&lt;/span&gt; &lt;span class="no"&gt;FailTwoSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="ss"&gt;start:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;FailTwoSeconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start_link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;]},&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can see that the module exists just to start up, wait 2 seconds, and crash.&lt;/p&gt;

&lt;p&gt;But crashing every 2 seconds is within the default intensity settings for Elixir.  So this module will go on crashing and being restarted til the cows come home.&lt;/p&gt;

&lt;p&gt;If you switch the sleep time to &lt;code&gt;1000&lt;/code&gt;, then it will trip the Supervisor's intensity limits and the Supervisor will say "I've had too much!" and shutdown.&lt;/p&gt;

&lt;p&gt;Thanks for reading and hope this saves you a headache one day! &lt;/p&gt;

</description>
      <category>elixir</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
