Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Masatoshi Nishiguchi
Masatoshi Nishiguchi

Posted on

     

[Elixir] GenServer Process management/registry

While I was learning Elixir basics, I was confused about how to manage process registration and discovery.
I got tons of ideas from the bookElixir in Action by Saša Juric.
Here is my study note on it.

There are multiple ways to manage processes.

1. no registration; remember the pid

  • We need to remember the pid that is returned when a genserver process is started.
  • We can create as many processes as we want from the same module.
  • We need to be aware that a pid will be changed when a process is terminated and recreated.
defmoduleMyApp.HelloServerdouseGenServerdefstart_link(id)doGenServer.start_link(__MODULE__,id)enddefhello(pid)doGenServer.call(pid,:hello)end@impltruedefinit(id)do{:ok,%{id:id}}end@impltruedefhandle_call(:hello,_from,state)do{:reply,"hello",state}endendiex>{:ok,pid}=MyApp.HelloServer.start_link(123){:ok,#PID<0.123.0>}iex>MyApp.HelloServer.hello(pid)"Hello"
Enter fullscreen modeExit fullscreen mode

2. using module name as local alias

  • This is suitable when we need only one process from a module.
  • Generally, we just use the module name as a local alias.
defmoduleMyApp.HelloServerLocalNamedouseGenServerdefstart_link(id)doGenServer.start_link(__MODULE__,id,name:__MODULE__)enddefhellodoGenServer.call(__MODULE__,:hello)end@impltruedefinit(id)do{:ok,%{id:id}}end@impltruedefhandle_call(:hello,_from,state)do{:reply,"hello",state}endendiex>MyApp.HelloServerLocalName.start_link(123){:ok,#PID<0.205.0>}iex>MyApp.HelloServerLocalName.hello()"Hello"iex>MyApp.HelloServerLocalName.start_link(123){:error,{:already_started,#PID<0.205.0>}}
Enter fullscreen modeExit fullscreen mode

3. using dynamic tuple as local alias (BAD)

When we want to register multiple processes, we may get tempted to generate an atom dynamically (I did); however it is not a good practice.
Erlang has a limit on the number of atoms we can create. Also atoms are not garbage-collected.

defmoduleMyApp.HelloServerDynamicNamedouseGenServerdefprocess_name(id)doString.to_atom("#{__MODULE__}_#{id}")enddefstart_link(id)doGenServer.start_link(__MODULE__,id,name:process_name(id))enddefhello(id)doGenServer.call(process_name(id),:hello)end@impltruedefinit(id)do{:ok,%{id:id}}end@impltruedefhandle_call(:hello,_from,state)do{:reply,"hello",state}endendiex>MyApp.HelloServerDynamicName.start_link(123){:ok,#PID<0.164.0>}iex>MyApp.HelloServerDynamicName.hello(123)"Hello"iex>:erlang.system_info(:atom_limit)1048576iex>:erlang.system_info(:atom_count)15849iex>(1..99)|>Enum.each(fnx->MyApp.HelloServerDynamicName.start_link(x)end):okiex>:erlang.system_info(:atom_count)16115
Enter fullscreen modeExit fullscreen mode

4. using Registry and via tuple

  • We can usevia_tuple in place of pid.
  • By using a composite key, many processes can be registered from the same module without creating extra atoms.
  • Obviously, a registry process needs to be started before the registration.
defmoduleMyApp.ProcessRegistrydodefvia_tuple(key)whenis_tuple(key)do{:via,Registry,{__MODULE__,key}}enddefwhereis_name(key)whenis_tuple(key)doRegistry.whereis_name({__MODULE__,key})enddefstart_link()doRegistry.start_link(keys::unique,name:__MODULE__)endenddefmoduleMyApp.HelloServerViaTupledouseGenServerdefvia_tuple(id)doMyApp.ProcessRegistry.via_tuple({__MODULE__,id})enddefwhereis(id)docaseMyApp.ProcessRegistry.whereis_name({__MODULE__,id})do:undefined->nilpid->pidendenddefstart_link(id)doGenServer.start_link(__MODULE__,id,name:via_tuple(id))enddefhello(id)doGenServer.call(via_tuple(id),:hello)end@impltruedefinit(id)do{:ok,%{id:id}}end@impltruedefhandle_call(:hello,_from,state)do{:reply,"hello",state}endendiex>MyApp.ProcessRegistry.start_link(){:ok,#PID<0.421.0>}iex>MyApp.HelloServerViaTuple.start_link(123){:ok,#PID<0.164.0>}iex>MyApp.HelloServerViaTuple.hello(123)"Hello"iex>MyApp.HelloServerViaTuple.whereis(123)#PID<0.164.0>
Enter fullscreen modeExit fullscreen mode

5. using global alias

  • A cluster-wide lock is set so the processes can be shared across multiple nodes.
defmoduleMyApp.HelloServerGlobalNamedouseGenServerdefwhereis(id)docase:global.whereis_name({__MODULE__,id})do:undefined->nilpid->pidendenddefregister_process(pid,id)docase:global.register_name({__MODULE__,id},pid)do:yes->{:ok,pid}:no->{:error,{:already_started,pid}}endenddefstart_link(id)docasewhereis(id)donil->{:ok,pid}=GenServer.start_link(__MODULE__,id)register_process(pid,id)pid->{:ok,pid}endenddefhello(id)doGenServer.call(whereis(id),:hello)end@impltruedefinit(id)do{:ok,%{id:id}}end@impltruedefhandle_call(:hello,_from,state)do{:reply,"hello",state}endendiex>MyApp.HelloServerGlobalName.start_link(123){:ok,#PID<0.205.0>}iex>MyApp.HelloServerGlobalName.hello(123)"Hello"iex>MyApp.HelloServerGlobalName.start_link(123){:error,{:already_started,#PID<0.205.0>}}
Enter fullscreen modeExit fullscreen mode

Starting a cluster

  • Open two iex shells
  • Turn BEAM instances (iex) into nodes
  • Make a cluster connecting those notes
iex--snamenode1@localhostiex(node2@localhost)>_
Enter fullscreen modeExit fullscreen mode
iex --sname node2@localhostiex(node2@localhost)> Node.connect(:node1@localhost)true
Enter fullscreen modeExit fullscreen mode

We can confirm processes are shared in two iex shells (BEAM instances).

Screen Shot 2020-12-10 at 8 55 20 AM

Finally

With this much info, I feel confident about handling processes. I'll keep on updating the post as soon as I learn something new that is relevant.

Happy coding!

Links

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

たのしむ
  • Location
    🇯🇵
  • Work
    ソフトウエアエンジニア
  • Joined

More fromMasatoshi Nishiguchi

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp