Elixir Supervisor Introduction

This is a simple introduction to OTP in Elixir.

The sample is based heavily upon Introducing Elixir.

This will demonstrate how Elixir keeps a server alive across code recompilation, and restores a server after it has crashed.

This assumes that you have installed Elixir.

On a mac you can install this with (there are other solutions on other platforms):

brew install elixir

Start by cloning the repo:

git clone https://github.com/chriseyre2000/drop_server.git

Change directory into the drop_server folder.

Type

iex -S mix

This will start the application running inside the interactive Elixir REPL.

This application has a DropServer.Worker being monitored by a supervisor.

First you can calculate the velocity after falling a distance in meters:

(Type the bit after the iex> prompts):

iex(1)> DropServer.Worker.calculate_drop(40)

{“ok”, 28.0}

iex(2)> DropServer.Worker.calculate_drop(41)

{“ok”, 28.347839423843222}

iex(3)> DropServer.Worker.calculate_drop(42)

{“ok”, 28.691462144686877}

iex(4)> DropServer.Worker.how_many_calls

So far calculated 3 velocities.

:ok

You can even recompile the DropServer.Worker while it is running:

iex(5)> c(“lib/drop_server/drop_server.ex”)

warning: redefining module DropServer.Worker (current version loaded from _build/dev/lib/drop_server/ebin/Elixir.DropServer.Worker.beam)

lib/drop_server/drop_server.ex:1

warning: redefining module DropServer.Worker.State (current version loaded from _build/dev/lib/drop_server/ebin/Elixir.DropServer.Worker.State.beam)

lib/drop_server/drop_server.ex:4

[DropServer.Worker, DropServer.Worker.State]

This even maintains the state:

iex(6)> DropServer.Worker.how_many_calls

So far calculated 3 velocities.

:ok

Now if you give it some invalid data Elixir will do the classic Erlang thing and let it crash!

iex(7)> DropServer.Worker.calculate_drop(-1)

21:49:21.278 [error] GenServer DropServer.Worker terminating

** (ArithmeticError) bad argument in arithmetic expression

(stdlib) :math.sqrt(-19.6)

(drop_server) lib/drop_server/drop_server.ex:44: DropServer.Worker.fall_velocity/1

(drop_server) lib/drop_server/drop_server.ex:20: DropServer.Worker.handle_call/3

(stdlib) gen_server.erl:661: :gen_server.try_handle_call/4

(stdlib) gen_server.erl:690: :gen_server.handle_msg/6

(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Last message (from #PID<0.133.0>): -1

State: %DropServer.Worker.State{count: 3}

Client #PID<0.133.0> is alive

(stdlib) gen.erl:169: :gen.do_call/4

(elixir) lib/gen_server.ex:921: GenServer.call/3

(stdlib) erl_eval.erl:680: :erl_eval.do_apply/6

(elixir) src/elixir.erl:265: :elixir.eval_forms/4

(iex) lib/iex/evaluator.ex:249: IEx.Evaluator.handle_eval/5

(iex) lib/iex/evaluator.ex:229: IEx.Evaluator.do_eval/3

(iex) lib/iex/evaluator.ex:207: IEx.Evaluator.eval/3

(iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1

** (exit) exited in: GenServer.call(DropServer.Worker, -1, 5000)

** (EXIT) an exception was raised:

** (ArithmeticError) bad argument in arithmetic expression

(stdlib) :math.sqrt(-19.6)

(drop_server) lib/drop_server/drop_server.ex:44: DropServer.Worker.fall_velocity/1

(drop_server) lib/drop_server/drop_server.ex:20: DropServer.Worker.handle_call/3

(stdlib) gen_server.erl:661: :gen_server.try_handle_call/4

(stdlib) gen_server.erl:690: :gen_server.handle_msg/6

(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

(elixir) lib/gen_server.ex:924: GenServer.call/3

However only the state is lost:

iex(7)> DropServer.Worker.how_many_calls

So far calculated 0 velocities.

:ok

iex(8)> DropServer.Worker.calculate_drop(10)

{“ok”, 14.0}

iex(9)> DropServer.Worker.how_many_calls

So far calculated 1 velocities.

:ok

The supervisor has restarted the server.

In a real service the state would have been kept in a distinct service possibly with some form of persistence.

80/20 Principle and Optimizing

The following is the means of finding the directory size of a folder and its contents on a mac:

du -s

This came in handy when I was trying to speed up a website deploy.

It turns out that over 98% of the content of the site was in one folder. Spliting this off an changing the copy policy saves between 50% and 75% of the deploy time.

Look for the quick wins!

Elixir Metaprogramming : the basics

Elixir has a very small core language. Most of what is thought of as the syntax is actually written using macros.

Elixir makes it ridiculously easy to get at the Abstract Syntax Tree (AST) of the code that you are using.

How to get the AST of some code:

iex(1)> quote do: 1 + 1
{:+, [context: Elixir, import: Kernel], [1, 1]}

New Machine Setup

I have recently moved jobs. This comes with the inevitable machine setup issue.

This is a list of things that I have been installing on my machine so that I won’t have to build myself another list:

  • Chrome
  • homebrew
  • neo4j
  • java8
  • elixir
  • exercism
  • vscode
    • Enable autosave (on the file menu)
    • GitLens
    • IntelliJ IDEA Keybindings
    • JS Refactor
  • Gradle
  • git ssh setup

After every mac os upgrade:

xcode-select –install