Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Elixir/OTP for PHP developers
Nacho Martín
My name is Nacho Martín.
I write code at Limenius.
We build tailor-made projects,
and provide consultancy and formation.
W...
Investing in a new language?
Learning alternatives
Learning alternatives Learning complements
Syntax?
Platform
Overall philosophy
Why was it built
Orientation of the community
(Simplified)
Request
Nginx
WrapperFastCGI PHPFastCGI
Response
WrapperFastCGI PHPFastCGI
Response
WrapperFastCGI PHPFastCGI
...
(Simplified)
Request
Nginx
WrapperFastCGI PHPFastCGI
Response
WrapperFastCGI PHPFastCGI
Response
WrapperFastCGI PHPFastCGI
...
Most of what we are going to say applies to both
Erlang:The Movie
Hello Mike.
Speaking about Elixir means speaking about Erlang
• Similar syntax.
• Battle tested.
• Very stable.
• More low-level feeli...
Elixir core features
Everything flows from Cheap processes
• Low footprint
• Fast start
• Isolated
• Share nothing
• Use as many as you need
pid = spawn(fn ->
IO.puts "In #{inspect self()} process"
end)
#PID<0.42.0>
pid = spawn(fn ->
IO.puts "In #{inspect self()} process"
end)
#PID<0.43.0>#PID<0.42.0>
Message passing
#PID<0.43.0>#PID<0.42.0>
send pid, {:hello, "world"}
receive do
{:hello, msg} -> msg
{:something, msg} -> ...
Monitors
Monitors
pid = spawn(fn ->
:timer.sleep 500
raise(“I’m dying.”)
end)
Monitors
pid = spawn(fn ->
:timer.sleep 500
raise(“I’m dying.”)
end)
Monitors
pid = spawn(fn ->
:timer.sleep 500
raise(“I’m dying.”)
end)
ref = Process.monitor(pid)
Monitors
pid = spawn(fn ->
:timer.sleep 500
raise(“I’m dying.”)
end)
ref = Process.monitor(pid)
Monitors
pid = spawn(fn ->
:timer.sleep 500
raise(“I’m dying.”)
end)
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :...
Monitors
pid = spawn(fn ->
:timer.sleep 500
raise(“I’m dying.”)
end)
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :...
Monitors
pid = spawn(fn ->
:timer.sleep 500
raise(“I’m dying.”)
end)
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :...
Links
Process.flag(:trap_exit, true)
spawn_link(fn ->
raise(“I am dying.”)
end)
Links
Process.flag(:trap_exit, true)
spawn_link(fn ->
raise(“I am dying.”)
end)
Links
Process.flag(:trap_exit, true)
spawn_link(fn ->
raise(“I am dying.”)
end)
receive do
{:EXIT, pid, msg} ->
IO.inspect...
Links
Process.flag(:trap_exit, true)
spawn_link(fn ->
raise(“I am dying.”)
end)
receive do
{:EXIT, pid, msg} ->
IO.inspect...
Links
Process.flag(:trap_exit, true)
spawn_link(fn ->
raise(“I am dying.”)
end)
receive do
{:EXIT, pid, msg} ->
IO.inspect...
😍OPEN TELECOM PLATFORM😍
OTP Supervision Trees
Supervisor
GenServerGenServerSupervisor
GenServerGenServer GenServer
{:ok, pid} = GenServer.start_link(Stack, [:hello])
GenServer
defmodule Stack do
use GenServer
@impl true
def init(stack) d...
{:ok, pid} = GenServer.start_link(Stack, [:hello])
GenServer
defmodule Stack do
use GenServer
@impl true
def init(stack) d...
{:ok, pid} = GenServer.start_link(Stack, [:hello])
GenServer
defmodule Stack do
use GenServer
@impl true
def init(stack) d...
{:ok, pid} = GenServer.start_link(Stack, [:hello])
GenServer.call(pid, :pop)
#=> :world
GenServer
defmodule Stack do
use G...
Supervisor
defmodule KV.Supervisor do
use Supervisor
def start_link(opts) do
Supervisor.start_link(__MODULE__, :ok, opts)
...
Supervision strategies
one_for_one
Supervision strategies
one_for_one
Supervision strategies
one_for_one
Supervision strategies
one_for_one
Supervision strategies
one_for_all
Supervision strategies
one_for_all
Supervision strategies
one_for_all
Supervision strategies
one_for_all
Supervision strategies
one_for_all
Supervision strategies
one_for_all
Supervision strategies
rest_for_all
Supervision strategies
rest_for_all
Supervision strategies
rest_for_all
Supervision strategies
rest_for_all
Supervision strategies
rest_for_all
Supervision strategies
rest_for_all
Let it crash vs defensive programming
:ok = do_something_that_can_crash
Not :ok? process crashes
Supervisors take care of ...
Distribution
Node.spawn_link :”bar@computer-name", fn -> Hello.world end
Node foo@computer-name Node bar@computer-name
Useful scenarios
Broadcast messages
PHP
User User’ User’’
Broadcast messages
PHP
User User’ User’’
Have a look at
Notify selected users
PHP
User User’’
Some auth
Presence
Sarah
Daniel
Ellen
3 min ago
Lukas
2 hours ago
PHP
User
DB
General case
PHP
User
DB
General case
PHP
User
DB
User’
General case
Thinking of problems as particular DBs
Focus in the dataFocus in the logic
Think as DB/cacheThink as app/game
Logic vs data
Focus in the dataFocus in the logic
Think as DB/cacheThink as app/game
It is a continuous:
We tend to be somewhere in the ...
Demo
Things to consider
• Not as easy as other platforms
• Not a massive language
• Releases & deployment difficult (compared wit...
To summarize
• Very different platform
• Very good for some problems
• Great source of ideas
• Useful to know even if we do...
To know more
• https://elixir-lang.org/ Especially the guide MIX AND OTP
• Phoenix Framework https://phoenixframework.org/...
Thanks! @nacmartin
nacho@limenius.com
Elixir/OTP for PHP developers
Elixir/OTP for PHP developers
Elixir/OTP for PHP developers
Upcoming SlideShare
Loading in …5
×

Elixir/OTP for PHP developers

Talk delivered at the Munich PHP User Group. An overview of the features of Elixir that may be more interesting for a PHP developer, so we focus in the platform, the cheap processes of the Erlang Virtual Machine, the philosophy of Let It Crash and how to model problems with trees of processes, and possible use cases.

  • Be the first to comment

  • Be the first to like this

Elixir/OTP for PHP developers

  1. 1. Elixir/OTP for PHP developers Nacho Martín
  2. 2. My name is Nacho Martín. I write code at Limenius. We build tailor-made projects, and provide consultancy and formation. We have been using PHP for many years. But for certain tasks we use Elixir/Erlang & we are very happy with it.
  3. 3. Investing in a new language?
  4. 4. Learning alternatives
  5. 5. Learning alternatives Learning complements
  6. 6. Syntax?
  7. 7. Platform Overall philosophy Why was it built Orientation of the community
  8. 8. (Simplified) Request Nginx WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response Socket
  9. 9. (Simplified) Request Nginx WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response WrapperFastCGI PHPFastCGI Response Socket ?
  10. 10. Most of what we are going to say applies to both
  11. 11. Erlang:The Movie Hello Mike.
  12. 12. Speaking about Elixir means speaking about Erlang • Similar syntax. • Battle tested. • Very stable. • More low-level feeling in code & community.
  13. 13. Elixir core features
  14. 14. Everything flows from Cheap processes • Low footprint • Fast start • Isolated • Share nothing • Use as many as you need
  15. 15. pid = spawn(fn -> IO.puts "In #{inspect self()} process" end) #PID<0.42.0>
  16. 16. pid = spawn(fn -> IO.puts "In #{inspect self()} process" end) #PID<0.43.0>#PID<0.42.0>
  17. 17. Message passing #PID<0.43.0>#PID<0.42.0> send pid, {:hello, "world"} receive do {:hello, msg} -> msg {:something, msg} -> "won't match" end
  18. 18. Monitors
  19. 19. Monitors pid = spawn(fn -> :timer.sleep 500 raise(“I’m dying.”) end)
  20. 20. Monitors pid = spawn(fn -> :timer.sleep 500 raise(“I’m dying.”) end)
  21. 21. Monitors pid = spawn(fn -> :timer.sleep 500 raise(“I’m dying.”) end) ref = Process.monitor(pid)
  22. 22. Monitors pid = spawn(fn -> :timer.sleep 500 raise(“I’m dying.”) end) ref = Process.monitor(pid)
  23. 23. Monitors pid = spawn(fn -> :timer.sleep 500 raise(“I’m dying.”) end) ref = Process.monitor(pid) receive do {:DOWN, ^ref, :process, ^pid, msg} -> IO.puts "Received :DOWN from #{inspect pid}" end
  24. 24. Monitors pid = spawn(fn -> :timer.sleep 500 raise(“I’m dying.”) end) ref = Process.monitor(pid) receive do {:DOWN, ^ref, :process, ^pid, msg} -> IO.puts "Received :DOWN from #{inspect pid}" end
  25. 25. Monitors pid = spawn(fn -> :timer.sleep 500 raise(“I’m dying.”) end) ref = Process.monitor(pid) receive do {:DOWN, ^ref, :process, ^pid, msg} -> IO.puts "Received :DOWN from #{inspect pid}" end
  26. 26. Links Process.flag(:trap_exit, true) spawn_link(fn -> raise(“I am dying.”) end)
  27. 27. Links Process.flag(:trap_exit, true) spawn_link(fn -> raise(“I am dying.”) end)
  28. 28. Links Process.flag(:trap_exit, true) spawn_link(fn -> raise(“I am dying.”) end) receive do {:EXIT, pid, msg} -> IO.inspect ":EXIT received from #{inspect pid}" IO.inspect msg end
  29. 29. Links Process.flag(:trap_exit, true) spawn_link(fn -> raise(“I am dying.”) end) receive do {:EXIT, pid, msg} -> IO.inspect ":EXIT received from #{inspect pid}" IO.inspect msg end
  30. 30. Links Process.flag(:trap_exit, true) spawn_link(fn -> raise(“I am dying.”) end) receive do {:EXIT, pid, msg} -> IO.inspect ":EXIT received from #{inspect pid}" IO.inspect msg end
  31. 31. 😍OPEN TELECOM PLATFORM😍
  32. 32. OTP Supervision Trees Supervisor GenServerGenServerSupervisor GenServerGenServer GenServer
  33. 33. {:ok, pid} = GenServer.start_link(Stack, [:hello]) GenServer defmodule Stack do use GenServer @impl true def init(stack) do {:ok, stack} end end Client GenServer
  34. 34. {:ok, pid} = GenServer.start_link(Stack, [:hello]) GenServer defmodule Stack do use GenServer @impl true def init(stack) do {:ok, stack} end end GenServer.call(pid, :pop) #=> :hello Client GenServer @impl true def handle_call(:pop, _from, [head | tail]) do {:reply, head, tail} end
  35. 35. {:ok, pid} = GenServer.start_link(Stack, [:hello]) GenServer defmodule Stack do use GenServer @impl true def init(stack) do {:ok, stack} end end GenServer.cast(pid, {:push, :world}) #=> :ok GenServer.call(pid, :pop) #=> :hello Client GenServer @impl true def handle_call(:pop, _from, [head | tail]) do {:reply, head, tail} end @impl true def handle_cast({:push, item}, state) do {:noreply, [item | state]} end
  36. 36. {:ok, pid} = GenServer.start_link(Stack, [:hello]) GenServer.call(pid, :pop) #=> :world GenServer defmodule Stack do use GenServer @impl true def init(stack) do {:ok, stack} end end GenServer.cast(pid, {:push, :world}) #=> :ok GenServer.call(pid, :pop) #=> :hello Client GenServer @impl true def handle_call(:pop, _from, [head | tail]) do {:reply, head, tail} end @impl true def handle_cast({:push, item}, state) do {:noreply, [item | state]} end
  37. 37. Supervisor defmodule KV.Supervisor do use Supervisor def start_link(opts) do Supervisor.start_link(__MODULE__, :ok, opts) end def init(:ok) do children = [ Stack, AnotherChild, AndAnother ] Supervisor.init(children, strategy: :one_for_one) end end
  38. 38. Supervision strategies one_for_one
  39. 39. Supervision strategies one_for_one
  40. 40. Supervision strategies one_for_one
  41. 41. Supervision strategies one_for_one
  42. 42. Supervision strategies one_for_all
  43. 43. Supervision strategies one_for_all
  44. 44. Supervision strategies one_for_all
  45. 45. Supervision strategies one_for_all
  46. 46. Supervision strategies one_for_all
  47. 47. Supervision strategies one_for_all
  48. 48. Supervision strategies rest_for_all
  49. 49. Supervision strategies rest_for_all
  50. 50. Supervision strategies rest_for_all
  51. 51. Supervision strategies rest_for_all
  52. 52. Supervision strategies rest_for_all
  53. 53. Supervision strategies rest_for_all
  54. 54. Let it crash vs defensive programming :ok = do_something_that_can_crash Not :ok? process crashes Supervisors take care of regenerating the system try { somethingThatCanCrash(); } catch (Exception $e) { recoverMaybe(); }
  55. 55. Distribution Node.spawn_link :”bar@computer-name", fn -> Hello.world end Node foo@computer-name Node bar@computer-name
  56. 56. Useful scenarios
  57. 57. Broadcast messages PHP User User’ User’’
  58. 58. Broadcast messages PHP User User’ User’’ Have a look at
  59. 59. Notify selected users PHP User User’’ Some auth
  60. 60. Presence Sarah Daniel Ellen 3 min ago Lukas 2 hours ago
  61. 61. PHP User DB General case
  62. 62. PHP User DB General case
  63. 63. PHP User DB User’ General case
  64. 64. Thinking of problems as particular DBs
  65. 65. Focus in the dataFocus in the logic Think as DB/cacheThink as app/game Logic vs data
  66. 66. Focus in the dataFocus in the logic Think as DB/cacheThink as app/game It is a continuous: We tend to be somewhere in the middle Logic vs data
  67. 67. Demo
  68. 68. Things to consider • Not as easy as other platforms • Not a massive language • Releases & deployment difficult (compared with PHP)
  69. 69. To summarize • Very different platform • Very good for some problems • Great source of ideas • Useful to know even if we don’t end up using it • And even if we don’t want to adopt these ideas!
  70. 70. To know more • https://elixir-lang.org/ Especially the guide MIX AND OTP • Phoenix Framework https://phoenixframework.org/ • Learn You Some Erlang for Great Good https://learnyousomeerlang.com/
  71. 71. Thanks! @nacmartin nacho@limenius.com

×