Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Erlang in The Land of Lisp

Erlang in The Land of Lisp

As seen on PolyConf 2016, Clojure Remote 2016 and :clojureD 2016.

This talk is dedicated to lessons we’ve learned while designing, developing, and deploying to production our very first Erlang project. The audience of this talk will learn about differences between Clojure and Erlang, both at the linguistic level as well as, even more importantly, at the level of underlying virtual machines. I’m going to discuss how Erlang challenges our methods of building systems in Clojure. I’ll use our new Erlang-based project as a source of concrete differences.

Video: https://www.youtube.com/watch?v=qVMKIKJrUd8

Jan Stępień

February 11, 2016
Tweet

More Decks by Jan Stępień

Other Decks in Programming

Transcript

  1. Erlang in the Land of Lisp
    with Jan Stępień @janstepien

    View Slide

  2. View Slide

  3. api.stylefruits.de
    ↑ ↓ ↑↑↑ ↓↓↓
    mobile client

    View Slide

  4. GET /v1/give-me-all-i-need-right-now
    Host: api.stylefruits.de
    Accept: applica on/truckload-of-json

    View Slide

  5. api.stylefruits.de
    ↑ ↓ ↑↑↑ ↓↓↓
    batching proxy
    ↑ ↓
    mobile client

    View Slide

  6. ↑↑↑ ↓↓↓
    HTTP client
    ↑↑↑ ↓↓↓
    JSON processing
    ↑ ↓
    HTTP server
    ↑ ↓

    View Slide

  7. ͜
    Rib
    Requests in Batches

    View Slide

  8. Erlang
    The syntax and the beauty beneath

    View Slide

  9. -module(qsort).
    -export([qsort/1]).
    qsort([]) -> [];
    qsort([Pivot|Rest]) ->
    qsort([Front || Front ++ [Pivot] ++
    qsort([Back || Back = Pivot]).
    en.wikipedia.org/wiki/Erlang (programming language)

    View Slide

  10. The Erlang VM
    where processes dwell
    p1 p2

    p4 ↔ p3

    View Slide

  11. CPU CPU CPU CPU
    sched sched sched sched
    p0 p1 p2 p3 p4 p5 p6 p7 p8 p9

    View Slide

  12. Processes’ heaps are separated
    p0 p1 p2 p3 p4 p5

    View Slide

  13. View Slide

  14. View Slide

  15. View Slide

  16. Back to Rib
    Se ng the environment up

    View Slide

  17. $ rebar create-app appid=rib
    ==> rib (create-app)
    Writing src/rib.app.src
    Writing src/rib_app.erl
    Writing src/rib_sup.erl

    View Slide

  18. %% rebar.config
    {deps,
    [{jiffy, ".*",
    {git,
    "git://github.com/davisp/jiffy",
    {tag, "0.13.3"}}},
    {ejsonpath, ".*",
    {git,
    "git://github.com/rustyio/sync",
    "de3c42df58"}}]}.

    View Slide

  19. $ rebar sh
    ==> rib (shell)
    Erlang/OTP 18
    Eshell V7.0 (abort with ^G)
    1> sync:go().
    Starting Sync (Automatic Code Compiler / Reloader)
    Scanning source files...
    ok
    2>
    =INFO REPORT==== 7-Feb-2016::12:21:23 ===
    src/rib.erl:0: Recompiled.
    =INFO REPORT==== 7-Feb-2016::12:21:23 ===
    rib: Reloaded! (Beam changed.)

    View Slide

  20. Elli
    and callback modules

    View Slide

  21. -module(elli_minimal_callback).
    -behaviour(elli_handler).
    handle(Req, _Args) ->
    handle(Req#req.method, elli_request:path(Req), Req).
    handle('GET',[<>, <>], _Req) ->
    {200, [], <>};
    handle(_, _, _Req) ->
    {404, [], <>}.
    github.com/knu n/elli

    View Slide

  22. Let’s make it all concurrent

    View Slide

  23. pmap(Fun, List) ->
    Parent = self(),
    Workers =
    [spawn(fun() ->
    Parent ! {self(), Fun(X)}
    end)
    || X [receive
    {Worker, Value} -> Value
    end
    || Worker

    View Slide

  24. pmap(Fun, List) ->
    Parent = self(),
    Workers =
    [spawn_link(fun() ->
    Parent ! {self(), Fun(X)}
    end)
    || X [receive
    {Worker, Value} -> Value
    end
    || Worker

    View Slide

  25. pmap(Fun, List) ->
    Parent = self(),
    Workers =
    [spawn_link(fun() ->
    Parent ! {self(), Fun(X)}
    end)
    || X [receive
    {Worker, Value} -> Value
    after
    1000 -> error(timeout)
    end
    || Worker

    View Slide

  26. You shall not
    !

    View Slide

  27. OTP
    and generic behaviours in par cular

    View Slide

  28. Use case
    HTTP connec on killer

    View Slide

  29. -module(rib_conn_killer).
    -export([start_link/0]).
    start_link() ->
    {ok, spawn_link(fun go/0)}.
    go() ->
    {ok, Url} = application:get_env(rib, backend),
    Headers = [{"connection", "close"}],
    {ok, _} = httpc:request(get, {Url, Headers}),
    ok = timer:sleep(30000),
    go().

    View Slide

  30. -module(rib_conn_killer_sup).
    -behaviour(supervisor).
    -export([start_link/0, init/1]).
    start_link() ->
    supervisor:start_link({local, ?MODULE},
    ?MODULE,
    []).
    init([]) ->
    {ok, {{one_for_one, 5, 10},
    [{rib_conn_killer, ...}]}}.

    View Slide

  31. Use case
    Request limiter

    View Slide

  32. -module(rib_limiter).
    -behaviour(gen_server).
    start_link(Opts) ->
    gen_server:start_link(?MODULE, Opts, []).
    subtract(ServerRef, N) ->
    gen_server:cast(ServerRef, {subtract, N}).
    init({max, N}) ->
    {ok, N}.
    handle_cast({subtract, N}, State) ->
    NewState = State - N,
    case NewState >= 0 of
    true -> {noreply, NewState};
    false -> {stop, limit_exceeded, NewState}
    end.

    View Slide

  33. Deployment
    Lightweight Docker images

    View Slide

  34. Something completely different
    Happy path programming, le ng it crash

    View Slide

  35. On shoulders of giants
    Virtual machine, OTP

    View Slide

  36. Needs more research
    Polymorphism, editor integra on

    View Slide

  37. Can’t stand the syntax?
    LFE, Joxa, Elixir

    View Slide

  38. github.com/stylefruits/rib

    View Slide

  39. Erlang in the Land of Lisp
    with Jan Stępień @janstepien

    View Slide