Resist
Reimplementing

OTP

Any sufficiently complicated

Erlang or elixir
program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of
OTP

What is OTP?

Patterns & Generic Abstractions over the Common Process

http://learnyousomeerlang.com/what-is-otp

Let's take a trip into implementing a stateful process in vanilla elixir

CraicStack

new()

{:ok, pid}

P

spawn

CraicStack

push(ref, value)

ref

ref :: pid | name

name :: atom()

value :: any()

{:push, value}

P

CraicStack

pop(ref)

value

from :: ref
ref :: pid | name

name :: atom()

value :: any()

{:pop, from}

P

{:pop_reply, value}

CraicStack

peek(ref)

value

ref :: pid | name

name :: atom()

value :: any()

{:peek, from}

P

{:peek_reply, value}

CraicStack

count(ref)

size

ref :: pid | name

name :: atom

size :: positive_integer

{:count, from}

P

{:count_reply, value}

mix new craic_stack
vim craic_stack
STEVEN GOTO VIM NOW...

Lets Look at

Observer and get our 

Mailbox working...

{:ok, stack} = CraicStack.new

:observer.start

for x <- 1..10_000_000, do: CraicStack.push(stack, x)

for _ <- 1..10_000_000, do: CraicStack.pop(stack) 

So out of the box vanilla elixir processes give us some instrumentation but as we will soon see there there is much we are missing out on

Error Scenario: Pop Crash

Our code is starting to look lame and bloated as we try to harden it, even though we are still embracing the
"Let it Crash"

philosphy

Did our Error capture any useful contextual information?

00:42:13.356 [error] Process #PID<0.95.0> raised an exception
** (MatchError) no match of right hand side value: []
    (craic_stack) lib/craic_stack.ex:57: CraicStack.handle/3
    (craic_stack) lib/craic_stack.ex:45: CraicStack.loop/1

What would our recovery scenario be if we want the stack to recover?

Even if we hand roll a solution to restart our process either through links, monitors, or our custom protocol it is still going to be reinventing the wheel... 

Any sufficiently complicated

Erlang or elixir
program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of
OTP

The point:

Let's do the same thing in OTP

vim craic_stack

Let's get a peek inside with Observer and some :sys calls

:sys.statistics(stack, :get)

{:ok,
 [start_time: {{2017, 1, 31}, {14, 39, 37}},
  current_time: {{2017, 1, 31}, {14, 40, 36}}, 
  reductions: 205, 
  messages_in: 2,
  messages_out: 0]}

When we recreate the same Error in GenServer version we get more details, such as last message and state

14:26:25.966 [error] GenServer #PID<0.120.0> terminating
** (MatchError) no match of right hand side value: []
    (craic_stack) lib/gen_stack.ex:43: GenStack.handle_call/3
    (stdlib) gen_server.erl:615: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:647: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: :pop
State: %{count: 0, store: []}

Let's Supervise our process and have that restart policy we have always dreamt of...

Why restart you ask?

Thats why...

Image Credit: High Throughput Erlang - Geoff Cant

Let's wrap our CraicStack in an Application so we can share the fun with all our OTP friends

Let's spin up our CraicStack Application and have a look with :observer

In conclusion... unless you are doing something highly bespoke, fall into the loving arms of OTP

For times when GenSever and GenEvent are just not enough there are Special Processes...

It is possible to make your custom processes play the OTP game, you just need to follow the OTP rules and leverage

:gen, :sys and :proc_lib
 

defmodule ProblemChild do
  use SpecialProcess

  def start_link do
    SpecialProcess.start_link(__MODULE__, :loop, [])
  end

  def loop do
    IO.puts "Yay I'm looping!"
    :timer.sleep(1000)
    loop
  end
end

An Elixir Macro that makes your process sing the OTP song 

"The benefits of using a special process is that the process can be part of a Supervision tree and will emit and handle proper system and error logger messages."

 

https://github.com/rbishop/special_process

 

Thanks for listening!

 

@holsee

holsee.github.com

 

code: github.com/holsee/craic_stack

 

Sponsored Book Raffle!

OTP

By Steven Holdsworth

OTP

Why you should embrace OTP in Elixir

  • 382