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

Real Time Web Application with Elixir and Phoenix

86f6cc36138b8f2706c28d9598e7e36c?s=47 kanmo
July 10, 2016

Real Time Web Application with Elixir and Phoenix

Developers.IO 2016 in Sapporoの発表資料です

86f6cc36138b8f2706c28d9598e7e36c?s=128

kanmo

July 10, 2016
Tweet

More Decks by kanmo

Other Decks in Technology

Transcript

  1. Real Time Web Application with Elixir and Phoenix Developers.IO 2016

    in Sapporo
  2. self introduction me |> name # Akihide Kan |> job

    # Software Engineer |> work_at # Classmethod, Inc. |> works # Ruby |> twitter # @kanmo
  3. Agenda • Elixir • Realtime Web • WebSocket • Phoenix

    • Channel • Sample Application • Demo
  4. Elixir?

  5. Introduction • ErlangͷVM্Ͱಈ͘Ruby෩ຯͷಈతͳؔ਺ܕݴޠ • ࡞ऀ͸Jose Valim(Railsίϛολ) • ଱ো֐ੑɺฒྻੑɺ෼ࢄੑೳʹ༏ΕΔ • ·ͩए͍ʢversion

    1.3ʣ • ϞμϯͳύοέʔδϚωʔδϟΛ࣋ͭ
  6. Features of Elixir • Pattern Matching • |> (Pipe Operator)

    • Immutable Data • Actor Model • OTP • Let it Crash
  7. Pattern Matching %{:name => company} = %{:name => “Classmethod”} IO.puts(company)

    # => Classmethod
  8. Pattern Matching %{:name => company} = %{:name => “Classmethod”} IO.puts(company)

    # => Classmethod ӈลͷ.BQͷLFZOBNF
  9. Pattern Matching %{:name => company} = %{:name => “Classmethod”} IO.puts(company)

    # => Classmethod ࠨลͷ.BQͷLFZOBNF ӈลͷ.BQͷLFZOBNF
  10. Pattern Matching %{:name => company} = %{:name => “Classmethod”} IO.puts(company)

    # => Classmethod ࠨลͷ.BQͷLFZOBNF ӈลͷ.BQͷLFZOBNF Ұகͨ͠৔߹ ʹม਺DPNQBOZ ʹz$MBTTNFUIPEΛଋറ
  11. Pattern Matching + Recursion defmodule MyList do def size([head|tail]), do:

    1 + size(tail) def size([]), do: 0 end MyList.size([“Elixir”, “Ruby”, “Java”]) # => 3ʢཁૉ਺͕ฦ٫͞ΕΔʣ
  12. Pattern Matching + Recursion defmodule MyList do def size([head|tail]), do:

    1 + size(tail) def size([]), do: 0 end MyList.size([“Elixir”, “Ruby”, “Java”]) # => 3ʢཁૉ਺͕ฦ٫͞ΕΔʣ IFBEʹϦετͷઌ಄ ཁૉz&MJYJSz͕ଋറ
  13. Pattern Matching + Recursion defmodule MyList do def size([head|tail]), do:

    1 + size(tail) def size([]), do: 0 end MyList.size([“Elixir”, “Ruby”, “Java”]) # => 3ʢཁૉ਺͕ฦ٫͞ΕΔʣ IFBEʹϦετͷઌ಄ ཁૉz&MJYJSz͕ଋറ UBJMʹ࢒Γͷཁૉ <z3VCZz z+BWBz>͕ଋറ
  14. Pattern Matching + Recursion defmodule MyList do def size([head|tail]), do:

    1 + size(tail) def size([]), do: 0 end MyList.size([“Elixir”, “Ruby”, “Java”]) # => 3ʢཁૉ਺͕ฦ٫͞ΕΔʣ IFBEʹϦετͷઌ಄ ཁૉz&MJYJSz͕ଋറ UBJMʹ࢒Γͷཁૉ <z3VCZz z+BWBz>͕ଋറ ΛՃࢉͯ͠ ࠶ؼݺͼग़͠
  15. Pattern Matching + Recursion defmodule MyList do def size([head|tail]), do:

    1 + size(tail) def size([]), do: 0 end MyList.size([“Elixir”, “Ruby”, “Java”]) # => 3ʢཁૉ਺͕ฦ٫͞ΕΔʣ IFBEʹϦετͷઌ಄ ཁૉz&MJYJSz͕ଋറ UBJMʹ࢒Γͷཁૉ <z3VCZz z+BWBz>͕ଋറ ΛՃࢉͯ͠ ࠶ؼݺͼग़͠ ཁૉ͕ۭʹͳͬͨΒऴྃ
  16. |> Pipe Operator 1..10 |> Enum.map(fn(x) -> x * x

    end) |> Enum.filter(fn(x) -> x < 40 end) |> IO.inspect # => [1,4,9,16,25,36] ؔ਺ͷฦ٫஋Λ࣍ͷؔ਺ͷ ୈҰҾ਺ʹ౉͢
  17. |> Pipe Operator defmodule Sample do def fetch_entry() do HTTPoison.get!(“http://b.hatena.ne.jp/entrylist/json?

    sort=count&url=http://dev.classmethod.jp”) |> decode_response |> extract_entry |> sort_descending_and_format end end
  18. |> Pipe Operator defmodule Sample do def fetch_entry() do HTTPoison.get!(“http://b.hatena.ne.jp/entrylist/json?

    sort=count&url=http://dev.classmethod.jp”) |> decode_response |> extract_entry |> sort_descending_and_format end end ͸ͯͿ"1*Λୟ͘
  19. |> Pipe Operator defmodule Sample do def fetch_entry() do HTTPoison.get!(“http://b.hatena.ne.jp/entrylist/json?

    sort=count&url=http://dev.classmethod.jp”) |> decode_response |> extract_entry |> sort_descending_and_format end end ͸ͯͿ"1*Λୟ͘ औಘ݁ՌΛ+40/ʹσίʔυ
  20. |> Pipe Operator defmodule Sample do def fetch_entry() do HTTPoison.get!(“http://b.hatena.ne.jp/entrylist/json?

    sort=count&url=http://dev.classmethod.jp”) |> decode_response |> extract_entry |> sort_descending_and_format end end ͸ͯͿ"1*Λୟ͘ औಘ݁ՌΛ+40/ʹσίʔυ λΠτϧͱϒΫϚ਺Λऔಘ
  21. |> Pipe Operator defmodule Sample do def fetch_entry() do HTTPoison.get!(“http://b.hatena.ne.jp/entrylist/json?

    sort=count&url=http://dev.classmethod.jp”) |> decode_response |> extract_entry |> sort_descending_and_format end end ͸ͯͿ"1*Λୟ͘ औಘ݁ՌΛ+40/ʹσίʔυ λΠτϧͱϒΫϚ਺Λऔಘ ࠷ޙʹιʔτͱจࣈྻ੔ܗ
  22. Immutable Data ฒߦϓϩάϥϛϯάΛ༰қʹ͢ΔͨΊʹɺσʔ λܕ͸ෆมʢഁյతૢ࡞͕Ͱ͖ͳ͍ʣ name = “kanmo” # => kanmo

    name2 = String.capitalize(name) # => Kanmo name #=> kanmo
  23. Actor Model • Actor(ܰྔϓϩηε)ؒͷσʔλڞ༗͸ϝοηʔ δύογϯά • Shared NothingͷϝϞϦϞσϧ • ஋͸ίϐʔ͞ΕΔͷͰϝϞϦڞ༗ͷ࢓૊Έ͕ෆཁ

    • ܰྔϓϩηε୯ҐͰGCʢFull GCൃੜ͠ͳ͍ʣ
  24. OTP • Actor Programmingͷ࣮૷Λαϙʔτ͢Δ ͨΊͷඪ४ϥΠϒϥϦʢErlangͷࢿ࢈ʣ • ͭ·Γύλʔϯ • SupervisorʹΑΔ؂ࢹͳͲ͕Ͱ͖Δ

  25. Let it Crash • ElixirͷΤϥʔઓུɺجຊతʹྫ֎ॲཧ͸͠ͳ͍ • ྫ֎ΛϋϯυϦϯά͠ͳͯ͘΋ΞϓϦέʔγϣϯશମ͕ crash͠ͳ͍ • ࣄલʹ࠶ىಈઓུΛઃఆ͢Δ

    • one_for_one: མͪͨϓϩηε͚ͩ࠶ىಈ • one_for_all:શͯͷࢠϓϩηεΛ࠶ىಈ • …
  26. Realtime Web

  27. –Wikipedia ϦΞϧλΠϜɾ΢Σϒ “ϦΞϧλΠϜɾ΢Σϒ͸ɺΠϯλʔωο τ্ͷϢʔβʔͷॻ͖ࠐΈ΍ಈ޲Λɺ ଈ͔࣌ͭେن໛ʹϢʔβʔͱڞ༗͢Δ࢓ ૊Έͷ૯শ”

  28. –Wikipedia ϦΞϧλΠϜɾ΢Σϒ “ϦΞϧλΠϜɾ΢Σϒ͸ɺΠϯλʔωο τ্ͷϢʔβʔͷॻ͖ࠐΈ΍ಈ޲Λɺ ଈ͔࣌ͭେن໛ʹϢʔβʔͱڞ༗͢Δ࢓ ૊Έͷ૯শ”

  29. ϦΞϧλΠϜWebͷಛ௃ • ΫϥΠΞϯτɺαʔό͕ৗ࣌઀ଓ • ΫϥΠΞϯτ͔ΒͰ͸ͳ͘ɺαʔό͔Β઀ ଓ͍ͯ͠ΔΫϥΠΞϯτ΁৘ใΛpush • ௨৴ͷස౓͕ଟ͍

  30. ϒϥ΢βͷϦΫΤετॲཧ 3FRVFTU 3FTQPOTF 4FSWFS • શͯͷϦΫΤετ͸ঢ়ଶΛ࣋ͨͳ͍ • server͸ϦΫΤετΛ৽͍͠΋ͷͱ ͯ͠ѻ͏

  31. ϒϥ΢βͷϦΫΤετॲཧ 3FRVFTU 3FTQPOTF 4FSWFS • શͯͷϦΫΤετ͸ঢ়ଶΛ࣋ͨͳ͍ • server͸ϦΫΤετΛ৽͍͠΋ͷͱ ͯ͠ѻ͏

  32. ϒϥ΢βͷϦΫΤετॲཧ 3FRVFTU 3FTQPOTF 4FSWFS • શͯͷϦΫΤετ͸ঢ়ଶΛ࣋ͨͳ͍ • server͸ϦΫΤετΛ৽͍͠΋ͷͱ ͯ͠ѻ͏ ঢ়ଶΛ࣋ͨͳ͍ͨΊɺ

    લճͷϦΫΤετɺϨεϙϯεͱ ͸ؔ܎ͳ͍
  33. ϦΞϧλΠϜ௨৴ͷ৔߹ 1BHF 4FSWFS • ΫϥΠΞϯτ͸௚઀αʔόͱҰͭͷϓϩηεͰ઀ଓ͢Δ • ΫϥΠΞϯτͷ਺͚ͩϓϩηεΛ্ཱͪ͛Δ • ૒ํ޲௨৴ՄೳͳίωΫγϣϯΛҡ࣋͢Δ •

    ΠϯλϥΫςΟϒͳΞϓϦέʔγϣϯʹଟ͍ߏ੒
 ʢGoogle Maps, forsquare…ʣ
  34. ϦΞϧλΠϜ௨৴ͷ৔߹ 1BHF 4FSWFS • ΫϥΠΞϯτ͸௚઀αʔόͱҰͭͷϓϩηεͰ઀ଓ͢Δ • ΫϥΠΞϯτͷ਺͚ͩϓϩηεΛ্ཱͪ͛Δ • ૒ํ޲௨৴ՄೳͳίωΫγϣϯΛҡ࣋͢Δ •

    ΠϯλϥΫςΟϒͳΞϓϦέʔγϣϯʹଟ͍ߏ੒
 ʢGoogle Maps, forsquare…ʣ ίωΫγϣϯཱ֬ ޙ͸ৗʹ઀ଓ
  35. WebSocket

  36. WebSocketͱ͸ • WebͰ૒ํ޲௨৴Λ͢Δ࢓૊Έ • HTTPʹൺ΂ͯখ͞ͳσʔλαΠζͰඞཁͳ ৘ใΛૹΔ͜ͱ͕Ͱ͖Δ • XMLHttpRequestͷ୅ΘΓʹͳΔ͜ͱ͕໨త

  37. WebSocketͱ͸ • TCPͱಉ͡Α͏ʹϋϯυγΣΠΫͰίωΫγϣϯཱ֬ • WebSocket Opening ϋϯυγΣΠΫ • ίωΫγϣϯཱ֬ޙɺWebSocketϓϩτίϧʹ੾Γସ͑Δ •

    ϑϨʔϜͱݺ͹ΕΔ୯ҐͰσʔλૹ৴ • ௿ίετʢpayload data͸࠷େ14byteʣ
  38. ίωΫγϣϯ։࢝ͷϦΫΤετ GET /resource HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade

    Sec-WebSocket-Version: 13 Sec-WebSocket-Key: kH/XISD+rj+uGkkQHBv/Dw== Ϩεϙϯε HTTP/1.1 101 OK Connection: Upgrade Upgrade: websocket sec-websocket-accept: ZCk6jJdyY474YOdCQNnFwjItvV0=
  39. ίωΫγϣϯ։࢝ͷϦΫΤετ GET /resource HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade

    Sec-WebSocket-Version: 13 Sec-WebSocket-Key: kH/XISD+rj+uGkkQHBv/Dw== Ϩεϙϯε HTTP/1.1 101 OK Connection: Upgrade Upgrade: websocket sec-websocket-accept: ZCk6jJdyY474YOdCQNnFwjItvV0= 6QHSBEFϔομͱ $POOFDUJPOϔομɻ )551͔ΒͷΞοϓάϨʔυΛҙຯ͢Δ
  40. ίωΫγϣϯ։࢝ͷϦΫΤετ GET /resource HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade

    Sec-WebSocket-Version: 13 Sec-WebSocket-Key: kH/XISD+rj+uGkkQHBv/Dw== Ϩεϙϯε HTTP/1.1 101 OK Connection: Upgrade Upgrade: websocket sec-websocket-accept: ZCk6jJdyY474YOdCQNnFwjItvV0= 6QHSBEFϔομͱ $POOFDUJPOϔομɻ )551͔ΒͷΞοϓάϨʔυΛҙຯ͢Δ 4UBUVT ͸TXJUDIJOHQSPUPDPMT ͷҙຯɻ
  41. ղܾ͠ͳ͍ͱ͍͚ͳ͍໰୊ • 1ΫϥΠΞϯτ1઀ଓΛҡ࣋͢Δ • ී௨ʹ࡞Δͱαʔόͷ୆਺Λ૿΍͢ඞཁ͕͋Δ • ϦΫΤετຖʹϓϩηεɺεϨουΛ্ཱͪ͛ ͯ͘ͱϝϞϦফඅ͕ଟ͘ഁ୼ • ௨৴ͷස౓͕ଟ͍෼ɺΤϥʔ΋ൃੜ͠΍͍͢

  42. Phoenix

  43. Introduction • Productive |> Reliable |> Fast
 ʢੜ࢈ੑɺ৴པੑɺεϐʔυΑ͠ʂʣ • ϦΞϧλΠϜ௨৴ͷαϙʔτɺσϑΥϧτ͸WebSocket

    Λ࢖͏ • RailsʹΠϯεύΠΞ͞Ε͍ͯΔ • ϑϧελοΫͳMVC Frameworkɺ։ൃελΠϧ΋͍ۙ
  44. Pros • Ұ୆ͷαʔόͰԿඦສͷίωΫγϣϯΛࡹ͘ύϑΥʔϚϯ ε • ҰͭͷActorʢܰྔϓϩηεʣΛҰͭͷTCPίωΫγϣϯ ʹׂΓ౰ͯΔ • ErlangVMͷ଱ো֐ੑɺActorຖͷGCʢFull GCͳ͠ʣɺ

    Let it CrashͳΤϥʔॲཧ
  45. Benchmark

  46. ֤ݴޠͷFWͱͷൺֱ ʢࢀߟ·Ͱʹʣhttps://gist.github.com/omnibs/e5e72b31e6bd25caf39a 'SBNFXPSL 5ISPVHIQVU SFRT -BUFODZ NT $POTJTUFODZ МNT 1IPFOJY

        1MBZ    &YQSFTT $MVTUFS    3BJMT   
  47. Request Pipeline

  48. PhoenixͷॲཧͷྲྀΕ • Phoenix͸ύΠϓϥΠϯͷΑ͏ʹϦΫΤε τʹରͯ͠ҰͭͣͭॲཧΛՃ޻͢Δ • ࠷ऴతʹՃ޻͞ΕͨϨεϙϯεΛฦ٫͢Δ • ҰͭҰͭͷॲཧΛ࣮ߦ͢Δ୯Ґ͕Plug

  49. Request Pipeline Connection |> endpoint |> router |> pipeline |>

    controller
  50. Request Pipeline Connection |> endpoint |> router |> pipeline |>

    controller ϦΫΤετ͕ಧ͘
  51. Request Pipeline Connection |> endpoint |> router |> pipeline |>

    controller ϦΫΤετ͕ಧ͘ ϦΫΤετΛৼΓ෼͚Δ
  52. Request Pipeline Connection |> endpoint |> router |> pipeline |>

    controller ϦΫΤετ͕ಧ͘ ϦΫΤετΛৼΓ෼͚Δ ڞ௨ॲཧΛϦΫΤε τʹରͯ͠ߦ͏
  53. Request Pipeline Connection |> endpoint |> router |> pipeline |>

    controller ϦΫΤετ͕ಧ͘ ϦΫΤετΛৼΓ෼͚Δ ڞ௨ॲཧΛϦΫΤε τʹରͯ͠ߦ͏ "DUJPOʹରԠ͢Δϩ δοΫΛ࣮ߦ
  54. Plug • Plug.Connߏ଄ମΛೖྗͯ͠Plug.Connߏ଄ମΛग़ ྗ͢Δ΋ͷΛPlugͱݺͿ • router΋controller΋plugͱ࣮ͯ͠૷͞Ε͍ͯΔ • endpointʹϦΫΤετ͕௨Δશͯͷॲཧ͕plugͱ ͯ͠ఆٛ͞Ε͍ͯΔ

  55. endpoint.ex defmodule Hello.Endpoint do use Phoenix.Endpoint, otp_app: :hello plug Plug.Static,

    ... plug Plug.RequestId plug Plug.Logger plug Plug.Parsers, ... plug Plug.MethodOverride plug Plug.Head plug Plug.Session, ... plug Hello.Router end
  56. endpoint.ex defmodule Hello.Endpoint do use Phoenix.Endpoint, otp_app: :hello plug Plug.Static,

    ... plug Plug.RequestId plug Plug.Logger plug Plug.Parsers, ... plug Plug.MethodOverride plug Plug.Head plug Plug.Session, ... plug Hello.Router end ॲཧ͢Δ1MVHΛࢦఆ
  57. router.ex defmodule Hello.Router do use Hello.Web, :router pipeline :browser do

    plug :accepts, [“html”] plug :fetch_session (লུ) end scope “/“ Hello do pipe_through :browser get “/“, PageController, :index end end
  58. router.ex defmodule Hello.Router do use Hello.Web, :router pipeline :browser do

    plug :accepts, [“html”] plug :fetch_session (লུ) end scope “/“ Hello do pipe_through :browser get “/“, PageController, :index end end ॲཧ͢Δ1MVH ؔ਺ Λࢦఆ
  59. router.ex defmodule Hello.Router do use Hello.Web, :router pipeline :browser do

    plug :accepts, [“html”] plug :fetch_session (লུ) end scope “/“ Hello do pipe_through :browser get “/“, PageController, :index end end ॲཧ͢Δ1MVH ؔ਺ Λࢦఆ ࢦఆͨ͠1MVHͷू·ΓΛ͜ͷϧʔ τͷϦΫΤετʹׂΓ౰ͯΔ
  60. ϦΫΤετ͕௨Δશͯͷॲཧ͸endpoint.exͱ router.exΛݟΕ͹͙͢ʹ෼͔Δ࡞Γʹͳ͍ͬͯ Δ

  61. Restart Strategies

  62. ྫɿ֎෦αʔϏεͷݺͼग़͠ • ϦΫΤετʹࣦഊͨ͠৔߹Ͳ͏͢Δ͔ʁ • ϦτϥΠʁ • ࣌ؒʹݫ͍͠ΞϓϦέʔγϣϯͷ৔߹ɺ ϦτϥΠ΋೉͍͠

  63. ෳ਺ͷϦΫΤετΛParallelʹ ౤͛Δ • 10ݸͷϦΫΤετΛ౤͛ͯҰࣦͭഊͯ͠΋ ແࢹͯ͠࢒Γͷ̕ݸͷϦΫΤετͷ͏ͪɺ ੒ޭͨ݁͠ՌΛ࠾༻͢Ε͹ྑ͍

  64. Τϥʔઓུ $MJFOU 8FC 4FSWJDF 4FSWFS

  65. Τϥʔઓུ $MJFOU 8FC 4FSWJDF 4FSWFS

  66. Τϥʔઓུ $MJFOU 8FC 4FSWJDF 4FSWFS ϦΫΤετΛෳ਺ૹ৴

  67. Τϥʔઓུ $MJFOU 8FC 4FSWJDF 4FSWFS Τϥʔ͕ൃੜͯ͠΋ ͦͷ··ແࢹ ❌ ϦΫΤετΛෳ਺ૹ৴

  68. Τϥʔઓུ $MJFOU 8FC 4FSWJDF 4FSWFS Τϥʔ͕ൃੜͯ͠΋ ͦͷ··ແࢹ ଞͷෳ਺ϦΫΤετ ͷ͏ͪ੒ޭͨ݁͠ՌΛ࠾༻ ❌

    ϦΫΤετΛෳ਺ૹ৴
  69. Τϥʔઓུ $MJFOU 8FC 4FSWJDF 4FSWFS Τϥʔ͕ൃੜͯ͠΋ ͦͷ··ແࢹ ଞͷෳ਺ϦΫΤετ ͷ͏ͪ੒ޭͨ݁͠ՌΛ࠾༻ ❌

    ϦΫΤετΛෳ਺ૹ৴
  70. ࠶ىಈͷ༗ແΛઃఆ defmodule Hello.ApiClient.Supervisor do use Supervisor def start_link() do Supervisor.start_link(__MODULE__,

    [], name: __MODULE__) end def init(_opts) do children = [worker(Hello.ApiClient, [], restart: :temporary)] supervise children, strategy, :simple_one_for_one end end
  71. ࠶ىಈͷ༗ແΛઃఆ defmodule Hello.ApiClient.Supervisor do use Supervisor def start_link() do Supervisor.start_link(__MODULE__,

    [], name: __MODULE__) end def init(_opts) do children = [worker(Hello.ApiClient, [], restart: :temporary)] supervise children, strategy, :simple_one_for_one end end ࠓճͷ৔߹͸ Τϥʔ͕ൃੜͯ͠΋࠶ىಈ͠ ͳ͍Α͏ʹઃఆ
  72. ࠶ىಈͷ༗ແΛઃఆ defmodule Hello.ApiClient.Supervisor do use Supervisor def start_link() do Supervisor.start_link(__MODULE__,

    [], name: __MODULE__) end def init(_opts) do children = [worker(Hello.ApiClient, [], restart: :temporary)] supervise children, strategy, :simple_one_for_one end end ࠓճͷ৔߹͸ Τϥʔ͕ൃੜͯ͠΋࠶ىಈ͠ ͳ͍Α͏ʹઃఆ ͜͜͸ࢠϓϩηεͷ؂ࢹ ͷઃఆ
  73. Timeoutઃఆ def await(childeren, opts) do timeout = opts[:timeout] || 5000

    timer = Process.send_after(self(), :timedout, timeout) .. end def await([head|tail], acc, timeout) do .. receive do :timeout -> kill(pid, monitor_ref) await(tail, acc, 0) end
  74. Timeoutઃఆ def await(childeren, opts) do timeout = opts[:timeout] || 5000

    timer = Process.send_after(self(), :timedout, timeout) .. end def await([head|tail], acc, timeout) do .. receive do :timeout -> kill(pid, monitor_ref) await(tail, acc, 0) end ࢠϓϩηεͷUJNFPVUͷ ઃఆ
  75. Timeoutઃఆ def await(childeren, opts) do timeout = opts[:timeout] || 5000

    timer = Process.send_after(self(), :timedout, timeout) .. end def await([head|tail], acc, timeout) do .. receive do :timeout -> kill(pid, monitor_ref) await(tail, acc, 0) end ࢠϓϩηεͷUJNFPVUͷ ઃఆ UJNFPVU͕ൃੜ ͨ͠ΒͦͷࢠϓϩηεΛLJMMͯ͠ ॲཧΛܧଓ
  76. Directory Structure

  77. DPOpH UFTU ʜ XFC MJC QSPKFDUSPPU DIBOOFMT DPOUSPMMFST NPEFMT TUBUJD

    UFNQMBUFT WJFXT Directory Tree
  78. ֤Directoryͷ໾ׂ • web: MVCॲཧʹؔΘΔϑΝΠϧΛஔ͘ • lib: supervision treeʹΑΓىಈ͢Δϓϩηεɺ௕͘ىಈ͠ଓ ͚ΔϓϩηεΛهड़ͨ͠ϑΝΠϧΛஔ͘
 ΞϓϦέʔγϣϯͷىಈɺऴ͕ྃઃఆ͞ΕͨϑΝΠϧ΋ஔ͘

    • config: ։ൃɺຊ൪ɺςετ؀ڥ͝ͱͷઃఆϑΝΠϧͳͲ͕ஔ ͔ΕΔ
  79. web directoryͷத • models, controllers,͸ଞͷFWͱಉ͡ • templates, views͸viewʹؔ͢ΔϑΝΠϧ • static͸੩తίϯςϯπͷஔ͖৔ॴ

    • channels͸real time௨৴ػೳͷϑΝΠϧ
  80. channel

  81. channel • Phoenix͕αϙʔτ͢ΔϦΞϧλΠϜ௨৴ػೳ • ૹ৴ऀ͸τϐοΫʹؔ͢ΔϝοηʔδΛϒϩʔ υΩϟετɺड৴ऀ͸τϐοΫΛߪಡͯ͠ϝο ηʔδΛड৴ • σϑΥϧτ͸WebSocketΛ࢖͏

  82. broadcast! 1BHF 4FSWFS 1BHF 1BHF 1BHF

  83. broadcast! 1BHF 4FSWFS 1BHF 1BHF 1BHF Πϕϯτൃੜ

  84. broadcast! 1BHF 4FSWFS 1BHF 1BHF 1BHF Πϕϯτൃੜ ϝοηʔδૹ৴

  85. broadcast! 1BHF 4FSWFS 1BHF 1BHF 1BHF ઀ଓ͍ͯ͠Δશ ΫϥΠΞϯτʹ ϝοηʔδૹ৴ Πϕϯτൃੜ

    ϝοηʔδૹ৴
  86. ChannelػೳΛ࣮ݱ͢Δ PhoenixͷParts

  87. Socket Handlers phoenix͸αʔόͱҰͭͷ઀ଓΛ࣋ͪɺͦͷ ઀ଓΛܦ༝ͯ͠ෳ਺ͷνϟϯωϧιέοτΛ ࣋ͭ

  88. Channel Routes ιέοτϋϯυϥʹϧʔτΛఆٛ͢Δ channel "sample_topic:*", HelloPhoenix.SampleTopicChannel

  89. Channels • ΫϥΠΞϯτ͔ΒͷΠϕϯτΛॲཧ͢Δɻ ϒϥ΢βͱҧ͍ϦΞϧλΠϜ௨৴͸ৗʹঢ় ଶΛอͪଓ͚ΔͷͰcontrollerͱผʹهड़͢ Δ

  90. Messages • topic: τϐοΫ͔τϐοΫ:αϒτϐοΫͷϖΞͷ໊લ ۭؒʢ”messages” or “messages:123) • event: จࣈྻͷΠϕϯτ໊ʢ”join”ʣ

    • payload: jsonܗࣜͷจࣈྻϝοηʔδ • ref: ड৴ͨ͠ΠϕϯτͷԠ౴ʹ࢖͏ϢχʔΫͳจࣈྻ
  91. Topic • ϝοηʔδΛਖ਼͍͠৔ॴ΁ૹΔͨΊͷࣝผ ࢠ • ଟ͘ͷ৔߹ɺusers:123 ͷΑ͏ʹϞσϧ૚ ͱͦͷϨίʔυIDͰτϐοΫΛ࡞Δ

  92. Transport • channelΛߦ͖དྷ͢Δ͢΂ͯͷϝοηʔδ Λѻ͏

  93. PubSub ΫϥΠΞϯτʹbroadcast͢Δ࢓૊ΈΛఏڙ ͢Δ

  94. Sample: Chat Application

  95. Chat Application ͜͜ʹΩϟϓνϟΛೖΕΔ hogeࢯ fugaࢯ http://phoenixchat.herokuapp.comΑΓ

  96. Chat Application ͜͜ʹΩϟϓνϟΛೖΕΔ <IPHF>͞Μͷ౤ߘ hogeࢯ fugaࢯ http://phoenixchat.herokuapp.comΑΓ

  97. Chat Application ͜͜ʹΩϟϓνϟΛೖΕΔ <IPHF>͞Μͷ౤ߘ <IPHF>͞Μͷ౤ߘ hogeࢯ fugaࢯ http://phoenixchat.herokuapp.comΑΓ

  98. Chat Application ͜͜ʹΩϟϓνϟΛೖΕΔ <IPHF>͞Μͷ౤ߘ <IPHF>͞Μͷ౤ߘ <GVHB>͞Μͷ౤ߘ hogeࢯ fugaࢯ http://phoenixchat.herokuapp.comΑΓ

  99. Chat Application ͜͜ʹΩϟϓνϟΛೖΕΔ <IPHF>͞Μͷ౤ߘ <IPHF>͞Μͷ౤ߘ <GVHB>͞Μͷ౤ߘ <GVHB>͞Μͷ౤ߘ hogeࢯ fugaࢯ http://phoenixchat.herokuapp.comΑΓ

  100. ॲཧͷྲྀΕ 1. ιέοτΛΤϯυϙΠϯτ΁Ϛ΢ϯτ 2. τϐοΫʹࢀՃ͢Δ 3. ΫϥΠΞϯτ͔ΒΠϕϯτૹ৴ 4. αʔό͔Β઀ଓ͍ͯ͠ΔଞͷΫϥΠΞϯτ ʹΠϕϯτૹ৴

  101. # lib/hello/endpoint.ex defmodule Hello.Endpoint do use Phoenix.Endopoint socket “/socket”, Hello.UserSocket

    . . . end # web/channels/user_socket.ex defmodule Hello.UserSocket do use Phoenix.Socket channel “rooms:*”, Hello.RoomChannel . . . end ιέοτΛϚ΢ϯτ
  102. # lib/hello/endpoint.ex defmodule Hello.Endpoint do use Phoenix.Endopoint socket “/socket”, Hello.UserSocket

    . . . end # web/channels/user_socket.ex defmodule Hello.UserSocket do use Phoenix.Socket channel “rooms:*”, Hello.RoomChannel . . . end ιέοτΛΤϯυϙΠϯτʹ Ϛ΢ϯτ ιέοτΛϚ΢ϯτ
  103. # lib/hello/endpoint.ex defmodule Hello.Endpoint do use Phoenix.Endopoint socket “/socket”, Hello.UserSocket

    . . . end # web/channels/user_socket.ex defmodule Hello.UserSocket do use Phoenix.Socket channel “rooms:*”, Hello.RoomChannel . . . end ιέοτΛΤϯυϙΠϯτʹ Ϛ΢ϯτ ΫϥΠΞϯτ͕zSPPNTz͔Β࢝ ·ΔτϐοΫͷϝοηʔδΛૹΔͱɺ 3PPN$IBOOFM΁ૹΒΕΔ ιέοτΛϚ΢ϯτ
  104. # web/channels/room_channel.ex defmodule Hello.RoomChannel do use Phoenix.Channel def join(“rooms:lobby”, auth_msg,

    socket) do {:ok, socket} end def end(“rooms:” <> _private_room_id, _auth_msg, socket) do {:error, %{reason: “unauthorized”}} end end τϐοΫʹࢀՃ
  105. # web/channels/room_channel.ex defmodule Hello.RoomChannel do use Phoenix.Channel def join(“rooms:lobby”, auth_msg,

    socket) do {:ok, socket} end def end(“rooms:” <> _private_room_id, _auth_msg, socket) do {:error, %{reason: “unauthorized”}} end end lSPPNTMPCCZzτϐοΫ ʹࢀՃ͢Δ τϐοΫʹࢀՃ
  106. # web/static/js/chat.js import {Socket} from “phoenix” let socket = new

    Socket(“/socket”) socket.connect let channel = socket.channel(“rooms:lobby”, {}) channel.join() .receive(“ok”, resp => { console.log(“Welcome to Chat!” }) ΫϥΠΞϯτ͔ΒτϐοΫʹࢀՃ
  107. # web/static/js/chat.js import {Socket} from “phoenix” let socket = new

    Socket(“/socket”) socket.connect let channel = socket.channel(“rooms:lobby”, {}) channel.join() .receive(“ok”, resp => { console.log(“Welcome to Chat!” }) ΫϥΠΞϯτ͔ΒτϐοΫʹࢀՃ ιέοτΛੜ੒ͯ͠ɺαʔ όʹ઀ଓ
  108. # web/static/js/chat.js import {Socket} from “phoenix” let socket = new

    Socket(“/socket”) socket.connect let channel = socket.channel(“rooms:lobby”, {}) channel.join() .receive(“ok”, resp => { console.log(“Welcome to Chat!” }) ΫϥΠΞϯτ͔Β DIBOOFMʹ઀ଓ ΫϥΠΞϯτ͔ΒτϐοΫʹࢀՃ ιέοτΛੜ੒ͯ͠ɺαʔ όʹ઀ଓ
  109. . . . chatInput.on("keypress", event => { if(event.keyCode === 13){

    channel.push(new_msg", {body: chatInput.val()}) chatInput.val("") } }) ΫϥΠΞϯτ͔ΒϝοηʔδΛૹ৴
  110. . . . chatInput.on("keypress", event => { if(event.keyCode === 13){

    channel.push(new_msg", {body: chatInput.val()}) chatInput.val("") } }) ઀ଓ͍ͯ͠ΔDIBOOFMʹ ϝοηʔδΛૹ৴ ΫϥΠΞϯτ͔ΒϝοηʔδΛૹ৴
  111. αʔόͰϝοηʔδड৴ αʔό͔ΒશΫϥΠΞϯτ΁broadcast # web/channels/room_channel.ex defmodule Toy.RoomChannel do use Phoenix.Channel .

    . . def handle_in("new_msg", %{"body" => body}, socket) do broadcast! socket, "new_msg", %{body: body} {:noreply, socket} end def handle_out("new_msg", payload, socket) do push socket, "new_msg", payload {:noreply, socket} end end
  112. αʔόͰϝοηʔδड৴ αʔό͔ΒશΫϥΠΞϯτ΁broadcast # web/channels/room_channel.ex defmodule Toy.RoomChannel do use Phoenix.Channel .

    . . def handle_in("new_msg", %{"body" => body}, socket) do broadcast! socket, "new_msg", %{body: body} {:noreply, socket} end def handle_out("new_msg", payload, socket) do push socket, "new_msg", payload {:noreply, socket} end end ΫϥΠΞϯτ͔Βͷ ϝοηʔδΛड৴
  113. αʔόͰϝοηʔδड৴ αʔό͔ΒશΫϥΠΞϯτ΁broadcast # web/channels/room_channel.ex defmodule Toy.RoomChannel do use Phoenix.Channel .

    . . def handle_in("new_msg", %{"body" => body}, socket) do broadcast! socket, "new_msg", %{body: body} {:noreply, socket} end def handle_out("new_msg", payload, socket) do push socket, "new_msg", payload {:noreply, socket} end end ΫϥΠΞϯτ͔Βͷ ϝοηʔδΛड৴ τϐοΫʹࢀՃ͠ ͍ͯΔશΫϥΠΞϯτʹ CSPBEDBTU
  114. . . . channel.on("new_msg", payload => { messagesContainer.append(`<br/>[${Date()}] ${payload.body}`) })

    αʔό͔ΒͷϝοηʔδΛड৴
  115. . . . channel.on("new_msg", payload => { messagesContainer.append(`<br/>[${Date()}] ${payload.body}`) })

    αʔό͔Βͷϝοηʔδ Λड৴ɺը໘ʹදࣔ αʔό͔ΒͷϝοηʔδΛड৴
  116. Demo

  117. ·ͱΊ

  118. Real Time Web • ϦΞϧλΠϜ௨৴ͷΞϓϦέʔγϣϯ͸ৗ࣌઀ଓʹ ͳΔ • Πϕϯτ͕ଟ͘ൃੜ͢ΔɺΤϥʔ΋ଟ͘ൃੜ͢Δ • খ͞ͳύέοτͷ΍ΓऔΓ͕ଟ͍

    • HTTPɺطଘͷWebΞϓϦέʔγϣϯͷ࢓૊ΈͰ͸ ࣮૷͢Δͷ͕ਏ͍
  119. Real Time Web • Πϕϯτ͸ଟ͘ൃੜ͢Δ͕ɺϖʔδભҠ͸΄ ͱΜͲൃੜ͠ͳ͍ɻҰͭͷίωΫγϣϯΛ࢖ ͍ଓ͚Δ • SPAͷܗͷΞϓϦέʔγϣϯͱ૬ੑ͕ྑ͍ؾ ͕͢Δ

  120. Phoenix • Phoenix + ElixirͰ͸σϑΥϧτͰϦΞϧλΠϜ௨ ৴ͷαϙʔτ͕͋Δ(+ WebSocket) • OTPɺActorʹΑΔ৴པੑͷߴ͞ͱΤϥʔॲཧ࣮૷ ͷ༰қ͞Ͱ։ൃऀ΋ԸܙΛड͚Δ

    • Full GCൃੜ͠ͳ͍ • Let it CrashͳΤϥʔॲཧ