austin elixir -- otp, rethinkdb, and phoenix channels

20
OTP, RethinkDB, and Phoenix Channels

Upload: preston-marshall

Post on 16-Apr-2017

1.673 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

OTP, RethinkDB, and Phoenix Channels

Page 2: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

My Background

• Rails-rider since 2008

• Used Erlang/OTP via RabbitMQ, ejabberd, etc for a long time

• Erlang/OTP never really "clicked"

• Accent is from Athens, Alabama, by way of Birmingham

Page 3: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Elixir

• Nicer Syntax

• Excellent build tools

• Macros (`use` especially)

• OTP wrappers

Page 4: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

OTP

• Open Telecom Platform

• Humongous

• Most commonly used libraries/behaviours

• supervisors

• gen_server

• gen_event

• gen_fsm

Page 5: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Supervisors

• Generally formed as trees

• Many restart strategies and knobs

• Supervises "workers"

• gen_servers

• Tasks

• other supervisors!

Page 6: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Money Trees

Page 7: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Erlang Ops

Credit ThisOTPLife.tumblr.com

Page 8: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

When the system keeps working through multiple partial failures

Credit ThisOTPLife.tumblr.com

Page 9: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

GenServer

• Generic Server

• It's a behaviour

• Implement the callbacks

• Elixir provides a nice wrapper

Page 10: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Naive Server

defmodule KeyValueStore do def start do ServerProcess.start(KeyValueStore) end

def put(pid, key, value) do ServerProcess.call(pid, {:put, key, value}) end

def get(pid, key) do ServerProcess.call(pid, {:get, key}) end

def init do HashDict.new end

def handle_call({:put, key, value}, state) do {:ok, HashDict.put(state, key, value)} end

def handle_call({:get, key}, state) do {HashDict.get(state, key), state} end end

Sample code from Elixir in Action by

Saša Jurić

Page 11: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Naive Serverdefmodule ServerProcess do def start(callback_module) do spawn(fn -> initial_state = callback_module.init loop(callback_module, initial_state) end) end

defp loop(callback_module, current_state) do receive do {request, caller} -> {response, new_state} = callback_module.handle_call( request, current_state )

send(caller, {:response, response}) loop(callback_module, new_state) end end

def call(server_pid, request) do send(server_pid, {request, self})

receive do {:response, response} -> response end end end

Sample code from Elixir in Action by

Saša Jurić

Page 12: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Improved with GenServerdefmodule KeyValueStore do use GenServer

def start do GenServer.start(KeyValueStore, nil) end

def put(pid, key, value) do GenServer.cast(pid, {:put, key, value}) end

def get(pid, key) do GenServer.call(pid, {:get, key}) end

def init(_) do {:ok, HashDict.new} end

def handle_cast({:put, key, value}, state) do {:noreply, HashDict.put(state, key, value)} end

def handle_call({:get, key}, _, state) do {:reply, HashDict.get(state, key), state} end end

Sample code from Elixir in Action by

Saša Jurić

Page 13: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

• Quickly becoming "Rails for Elixir,"

• Simpler and easy to understand

• Routing, Templating, and Models

• Channels!

Page 14: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Phoenix Channels

• Another behaviour

• Quite a bit like GenServers

• Bi-directional controllers

• Persistent connection with the client (browser, mobile, IoT)

Page 15: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

RethinkDB

• JSON database from the ground up

• LINQ-like queries

• Scaling, Sharding, Replication across datacenters

• Changefeeds!

Page 16: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Changefeeds

• Real-time stream of changes

• Subscribe to table, document, or an arbitrary query

• Aggregation support in the works

• Changefeeds and Phoenix channels work great together

Page 17: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Tweets Changefeed Query

import RethinkDB.Query require RethinkDB.Lambda import RethinkDB.Lambda db("elixirfriends") |> table("tweets") |> changes |> ElixirFriends.Database.run |> Stream.take_every(1) |> Enum.each fn(change) -> %{"new_val" => post} = change html = Phoenix.View.render_to_string ElixirFriends.PostView, "_post.html", post: post push socket, "tweet", %{view: html} end

Page 18: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Javascript

import {Socket} from "phoenix" let socket = new Socket("/ws") socket.connect() let chan = socket.chan("tweets") chan.join().receive("ok", chan => { console.log(`Subscribed to tweets`) }) chan.on("tweet", function(msg) { console.log(msg) $('#tweets').prepend(msg.view); }) let App = {} export default App

Page 19: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Live Demo

Page 20: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels

Conclusion

• OTP provides the building blocks

• Elixir makes them easy to use

• Phoenix is awesome

• Phoenix Channels and RethinkDB changefeeds make a supremely unique pair