--- title: e2 --- {% from "deckjs.html" import section with context %} {% call section('--------------- First Page ----------------------') %} ## e2 ### Erlang Factory - San Fran Bay Area, 2012 ### Garrett Smith ### CloudBees {% endcall %} {% call section('--------------- Hill 1 --------------------------') %} ## A Hard Problem {% endcall %} {% call section('--------------- Hill 2 --------------------------') %} ## A Less Hard Problem {% endcall %} {% call section('--------------- Hill 3 --------------------------') %} ## You Can Do It! {% endcall %} {% call section('--------------- Top of Hill ---------------------') %} ## Solved! {% endcall %} {% call section('--------------- Bumper - Main Point -------------') %} # Hard Problems -> Small Problems {% endcall %} {% call section('--------------- Organic Complexity --------------') %} ## Proof {% endcall %} {% call section('--------------- I Heart Erlang ------------------') %} ## Which Is Why {% endcall %} {% call section('--------------- Challenges ----------------------') %} ## Some Challenges with Erlang * OTP has lots of moving parts * Not clear where to start {% endcall %} {% call section('--------------- Goals ---------------------------') %} ## e2 Goals * Help people use Erlang/OTP more effectively * Reduce boilerplate by using sensible defaults * Simplified API (e.g. options vs tuples) * Provide useful, high level abstractions {% endcall %} {% call section('--------------- Non-Goals -----------------------') %} ## e2 Non Goals * Change for the sake of change * Undermine Erlang/OTP * Change syntax or semantics * Magic {% endcall %} {% call section('--------------- Status --------------------------') %} ## e2 Status * Feature complete * Running in production at CloudBees for several months * No known issues * Meeting its goals {% endcall %} {% call section('--------------- Process Types -------------------') %} ## e2 Process Types ### Service Starts, waits for messages ### Task Starts, does something {% endcall %} {% call section('--------------- Proof by Analogy ----------------') %} ## Why This Will Work ### Service = Daemon ### Task = Job {% endcall %} {% call section('--------------- Code Section Bumper -------------') %} # Code Comparisons {% endcall %} {% call section('--------------- gen_server example --------------') %} ## gen_server :::erlang -module(gen_server_skel). -behaviour(gen_server). -export([start_link/0]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, ...]). -record(state, {}). start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). init([]) -> {ok, #state{}}. handle_call(_Request, _From, State) -> {reply, ok, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. {% endcall %} {% call section('--------------- e2_service example --------------') %} ## e2_service :::erlang -module(e2_service_skel). -export([start_link/0]). -export([handle_msg/3]). -record(state, {}). start_link() -> e2_service:start_link(?MODULE, #state{}, [registered]). handle_msg(_Msg, _From, State) -> {noreply, State}. {% endcall %} {% call section('--------------- e2_service w/init ----------------') %} ## e2_service + init :::erlang -module(e2_service_skel). -export([start_link/0]). -export([init/1, handle_msg/3]). -record(state, {}). start_link() -> e2_service:start_link(?MODULE, [], [registered]). init([]) -> {ok, #state{}}. handle_msg(_Msg, _From, State) -> {noreply, State}. {% endcall %} {% call section('--------------- e2_service w/terminate -----------') %} ## e2_service + terminate :::erlang -module(e2_service_skel). -export([start_link/0]). -export([init/1, handle_msg/3, terminate/2]). -record(state, {}). start_link() -> e2_service:start_link(?MODULE, [], [registered]). init([]) -> {ok, #state{}}. handle_msg(_Msg, _From, State) -> {noreply, State}. terminate(_Reason, State) -> ok. {% endcall %} {% call section('--------------- gen_service w/init hack ----------') %} ## init timeout hack :::erlang -module(timeout_hack). -behaviour(gen_server). -export([start_link/0, init/1, handle_info/2, ...]). start_link() -> gen_server:start_link(?MODULE, [], []). init([]) -> {ok, #state{}, 0}. handle_info(timeout, State) -> %% do work {stop, normal, State}. ... {% endcall %} {% call section('--------------- e2_task example -----------------') %} ## e2_task :::erlang -module(e2_task_skel). -behaviour(e2_task). -export([start_link/0, handle_task/1]). start_link() -> e2_task:start_link(?MODULE, []). handle_task(State) -> %% do work {stop, normal, State}. {% endcall %} {% call section('--------------- e2_task w/repeat -----------------') %} ## e2_task + repeat every 5 seconds :::erlang -module(e2_task_skel). -behaviour(e2_task). -export([start_link/0, handle_task/1]). start_link() -> e2_task:start_link(?MODULE, [], [{repeat, 5000}]). handle_task(State) -> %% do work {repeat, State}. {% endcall %} {% call section('--------------- e2_task w/delay ------------------') %} ## e2_task + initial 5 second delay :::erlang -module(e2_task_skel). -behaviour(e2_task). -export([start_link/0, handle_task/1]). start_link() -> e2_task:start_link(?MODULE, [], [{delay, 5000}]). handle_task(State) -> %% do work {repeat, State}. {% endcall %} {% call section('--------------- supervisor example --------------') %} ## supervisor :::erlang -module(supervisor_skel). -behaviour(supervisor). -export([start_link/0]). -export([init/1]). start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). init([]) -> {ok, {one_for_one, 1000, 3600}, [{hello, {hello, start_link, []}, permanent, brutal_kill, worker, [hello]}]}. {% endcall %} {% call section('--------------- e2_supervisor example -----------') %} ## e2_supervisor :::erlang -module(e2_supervisor_skel). -export([start_link/0]). start_link() -> e2_supervisor:start_link(?MODULE, [hello]). {% endcall %} {% call section('--------------- e2_supervisor w/child opts -------') %} ## e2_supervisor + child options :::erlang -module(e2_supervisor_skel). -export([start_link/0]). start_link() -> e2_supervisor:start_link( ?MODULE, [{hello, [{shutdown, 1000}, {restart, temporary}]}]). {% endcall %} {% call section('--------------- e2_supervisor w/start args -------') %} ## e2_supervisor + child start args :::erlang -module(e2_supervisor_skel). -export([start_link/0]). start_link() -> e2_supervisor:start_link( ?MODULE, [{{'{{'}}hello, start_link, ["Hi!"]}, [{shutdown, 1000}, {restart, temporary}]}]). {% endcall %} {% call section('--------------- e2_supervisor w/options ----------') %} ## e2_supervisor + options :::erlang -module(e2_supervisor_skel). -export([start_link/0]). start_link() -> e2_supervisor:start_link( ?MODULE, [hello], [{strategy, one_for_all}]). {% endcall %} {% call section('--------------- e2_task_supervisor --------------') %} ## e2_task_supervisor :::erlang -module(e2_supervisor_skel). -export([start_link/0]). start_link() -> e2_supervisor:start_link( ?MODULE, [hello], [{strategy, one_for_all}]). {% endcall %} {% call section('--------------- Other Functions Bumper ----------') %} # Other Facilities {% endcall %} {% call section('--------------- e2_log --------------------------') %} ## e2_log 1> e2_log:info("Hello Erlang!"). ok =INFO REPORT==== 29-Mar-2012::20:17:38 === Hello Erlang! 2> e2_log:info("Hello ~s!~n", ["Erlang"]). ok 3> =INFO REPORT==== 29-Mar-2012::20:17:57 === Hello Erlang! 3> e2_log:info({msg, "Hello Erlang!"}). ok 4> =INFO REPORT==== 29-Mar-2012::20:18:10 === {msg,"Hello Erlang!"} {% endcall %} {% call section('--------------- e2_log_handler ------------------') %} ## e2_log_handler :::erlang -module(syslog_handler). -behavior(e2_log_handler). -export([install/0]). -export([init/1, handle_event/2]). install() -> e2_log:add_handler(?MODULE). init([]) -> ok = syslog:open("e2_logger_example", [], local0), {ok, []}. handle_event({error_msg, Msg}, State) -> syslog:log(err, format_msg(Msg)); handle_event({error_report, Report}, State) -> syslog:log(err, format_report(Report)); ... {% endcall %} {% call section('--------------- e2_opt --------------------------') %} ## e2_opt ### Sample Schema :::erlang -define(STRATEGIES, [one_for_all, one_for_one, rest_for_one, simple_one_for_one]). -define(SCHEMA, [{strategy, [{values, ?STRATEGIES}, implicit, {default, one_for_one}]}, {max_restart, [{validate, fun validate_max_restart/1}, {default, {1, 1}}]}, {registered, [{default, undefined}]}]). ### Sample Use :::erlang Opts = e2_opt:validate([{strategy, one_for_one}, registered], ?SCHEMA), one_for_one = e2_opt:value(strategy, Opts), undefined = e2_opt:value(registered, Opts) {% endcall %} {% call section('--------------- Planned -------------------------') %} ## Planned * Improved docs * Lots more tutorials (how to build *this*) * More project templates * Add some missing function support (minor) {% endcall %} {% call section('--------------- Possible ------------------------') %} ## Possible * gen_server variants * Global registrations * gen_fsm * Code reloading (i.e. exposing `code_changed/2`) * Worker pools * Other low level "app building" facilities * e2 + 0MQ support (separate project/app) {% endcall %} {% call section('--------------- Getting Started -----------------') %} ## Where Do I Start?
http://e2project.org
{% endcall %}