72 lines
2.6 KiB
Elixir
72 lines
2.6 KiB
Elixir
# register a process that can store key, value pairs
|
|
Registry.start_link(name: R, keys: :duplicate)
|
|
|
|
# register(register_name, key, value)
|
|
Register.register(R, "hello", "world")
|
|
Register.lookup(R, "hello")
|
|
|
|
# here we can associate a name, with a process ID
|
|
# can allow us to dynamically start any number of Workers
|
|
Registry.register(R, {Counter.Worker, "c1"})
|
|
|
|
f = fn (k, v) -> spawn(fn -> Registry.register(R, k, v); Process.sleep(30_000) end) end
|
|
pid = f.(:abc, 1)
|
|
Registry.keys(R, pid) # get all the keys for a PID -> [:abc]
|
|
Process.alive?(pid) # once dead i.e. returns -> false then:
|
|
Registry.keys(R, pid) # the process ID will be gone, -> [] not [:abc]
|
|
|
|
|
|
# Using our dynamic_counters implementation we have a counter server
|
|
# that is fault tolerant, i.e. if a worker dies, they will restart
|
|
DynamicSupervisor.start_child(Counter.DynamicSupervisor, {Counter.Worker, "c1"})
|
|
# -> {:ok, #PID<0.147.0>}
|
|
{_, pid} = v
|
|
# -> {:ok, #PID<0.147.0>}
|
|
Counter.Worker.inc("c1")
|
|
# -> :ok
|
|
Counter.Worker.inc("c1")
|
|
# -> :ok
|
|
Counter.Worker.value("c1")
|
|
# -> 2
|
|
|
|
# we can crash and see it restarts
|
|
Counter.Worker.inc("c1", "hello")
|
|
# -> :ok
|
|
|
|
# 10:04:25.932 [error] GenServer {Counter.Registry, {Counter.Worker, "c1"}} terminating
|
|
# ** (ArithmeticError) bad argument in arithmetic expression
|
|
# :erlang.+(2, "hello")
|
|
# (dynamic_counters 0.1.0) lib/dynamic_counters/worker.ex:37: Counter.Worker.handle_cast/2
|
|
# (stdlib 6.2.2.5) gen_server.erl:2371: :gen_server.try_handle_cast/3
|
|
# (stdlib 6.2.2.5) gen_server.erl:2433: :gen_server.handle_msg/6
|
|
# (stdlib 6.2.2.5) proc_lib.erl:329: :proc_lib.init_p_do_apply/3
|
|
# Last message: {:"$gen_cast", {:inc, "hello"}}
|
|
# State: 2
|
|
Counter.Worker.value("c1")
|
|
# -> 0 has restarted without retaining state
|
|
Enum.each(1..100_000, fn n -> DynamicSupervisor.start_child(Counter.DynamicSupervisor, {Counter.Worker, "d#{n}"}) end )
|
|
# -> :ok
|
|
Enum.each(1..100_000, fn n -> Counter.Worker.inc("d#{n}", n) end)
|
|
# -> :ok
|
|
Enum.map(1..10, fn n -> Counter.Worker.value("d#{n}") end)
|
|
# -> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
|
|
|
|
### Erlang Term Store
|
|
t = :ets.new(T, [])
|
|
# you can insert tuples of any number of elements, but typically just a key, value pair
|
|
# by default you cannot have duplicate keys
|
|
:ets.insert(t, {:a, 1})
|
|
:ets.lookup(t, :a) # -> [a: 1] lookup only matches the first element of a tuple
|
|
:ets.insert(t, {"hello", 2, :abc})
|
|
|
|
:ets.tab2list(t) # -> [{a: 2}, {"hello, 2, :abc}]
|
|
:ets.insert(t, {"world", 3, :xyz})
|
|
:ets.match_object(t, {"hello", :_, :_}) # -> [{"hello", 2, :abc}]
|
|
|
|
:ets.new(T, [:named_table, :public]) # can also use a named table and not need to assign to something like t
|
|
:ets.insert(T, {:abc, 123})
|
|
:ets.lookup(T, :abc);
|
|
|
|
System.schedulers_online()
|