austin elixir -- otp, rethinkdb, and phoenix channels
TRANSCRIPT
![Page 1: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/1.jpg)
OTP, RethinkDB, and Phoenix Channels
![Page 2: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/2.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/3.jpg)
Elixir
• Nicer Syntax
• Excellent build tools
• Macros (`use` especially)
• OTP wrappers
![Page 4: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/4.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/5.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/6.jpg)
Money Trees
![Page 8: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/8.jpg)
When the system keeps working through multiple partial failures
Credit ThisOTPLife.tumblr.com
![Page 9: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/9.jpg)
GenServer
• Generic Server
• It's a behaviour
• Implement the callbacks
• Elixir provides a nice wrapper
![Page 10: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/10.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/11.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/12.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/13.jpg)
• Quickly becoming "Rails for Elixir,"
• Simpler and easy to understand
• Routing, Templating, and Models
• Channels!
![Page 14: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/14.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/15.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/16.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/17.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/18.jpg)
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](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/19.jpg)
Live Demo
![Page 20: Austin Elixir -- OTP, RethinkDB, and Phoenix Channels](https://reader031.vdocument.in/reader031/viewer/2022022412/58f31aa61a28ab0c318b4597/html5/thumbnails/20.jpg)
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