diff options
author | Thomas Letan <contact@thomasletan.fr> | 2018-05-01 23:02:24 +0200 |
---|---|---|
committer | Thomas Letan <contact@thomasletan.fr> | 2018-05-01 23:02:24 +0200 |
commit | d4f61d0f54ba171c9716d59cdb1e7c6f9cd48a41 (patch) | |
tree | 3b99074485e9de97f0dd35e9de8df868588b3b0f | |
parent | release: lkn_core 0.4.2 (diff) |
feature: Use Instance as proxy for reaching Systems
This patch is a good step towards reducing the risk of race condition,
regarding the insertion of new puppets in a given instance. Indeed,
the `register_puppet` functions of `System` is blocking (it is a
`call`), therefore an Instance will not be able to deal with proxy
requests targeting Systems before the new puppet has been registered
to each Systems.
-rw-r--r-- | lib/lkn/core/instance.ex | 20 | ||||
-rw-r--r-- | lib/lkn/core/specs.ex | 65 | ||||
-rw-r--r-- | lib/lkn/core/system.ex | 7 |
3 files changed, 73 insertions, 19 deletions
diff --git a/lib/lkn/core/instance.ex b/lib/lkn/core/instance.ex index 6174998..264c7ae 100644 --- a/lib/lkn/core/instance.ex +++ b/lib/lkn/core/instance.ex @@ -343,6 +343,11 @@ defmodule Lkn.Core.Instance do {:reply, true, state} end end + def handle_call({:proxy_call, to, msg}, _from, state) do + res = GenServer.call(to, msg) + + {:reply, res, state} + end def handle_call({:unregister_puppet, puppet_key}, _from, state) do state = if MapSet.member?(state.puppets, puppet_key) do # unregister the pupet from each systems @@ -385,8 +390,23 @@ defmodule Lkn.Core.Instance do {:noreply, state} end + def handle_cast({:proxy_cast, to, message}, state) do + GenServer.cast(to, message) + + {:noreply, state} + end def notify_puppeteers(instance_key, notif) do GenServer.cast(Name.instance(instance_key), {:notify_group, notif}) end + + @doc false + def proxy_cast(instance_key, target, message) do + GenServer.cast(Name.instance(instance_key), {:proxy_cast, target, message}) + end + + @doc false + def proxy_call(instance_key, target, message) do + GenServer.call(Name.instance(instance_key), {:proxy_call, target, message}) + end end diff --git a/lib/lkn/core/specs.ex b/lib/lkn/core/specs.ex index 3471d4c..7b16945 100644 --- a/lib/lkn/core/specs.ex +++ b/lib/lkn/core/specs.ex @@ -45,7 +45,7 @@ defmodule Lkn.Core.Specs do plugin = quote do :plugin end - casts_client = Enum.map(casts, &(cast_client(plugin, var_name(key_name), key_type, key_to_name, &1))) + casts_client = Enum.map(casts, &(cast_client(plugin, var_name(key_name), key_type, key_to_name, nil, &1))) casts_behaviour = Enum.map(casts, &(cast_server(&1, var_name(key_name), key_type, additional_args, state_type, "_plugin"))) quote do @@ -79,11 +79,12 @@ defmodule Lkn.Core.Specs do impl_suffix = Keyword.get(keywords, :impl_suffix, "") key_name = Keyword.get(keywords, :key_name, var_name("key")) additional_args = Keyword.get(keywords, :additional_args, []) + proxy_name = Keyword.fetch(keywords, :proxy_names) spec = quote do :spec end - casts_client = Enum.map(casts, &(cast_client(spec, key_name, key_type, key_to_name, &1))) - calls_client = Enum.map(calls, &(call_client(spec, key_name, key_type, key_to_name, &1))) + casts_client = Enum.map(casts, &(cast_client(spec, key_name, key_type, key_to_name, proxy_name, &1))) + calls_client = Enum.map(calls, &(call_client(spec, key_name, key_type, key_to_name, proxy_name, &1))) casts_behaviour = Enum.map(casts, &(cast_server(&1, key_name, key_type, additional_args, state_type, impl_suffix))) calls_behaviour = Enum.map(calls, &(call_behaviour(&1, key_name, key_type, additional_args, state_type))) @@ -97,7 +98,7 @@ defmodule Lkn.Core.Specs do end end - defp cast_client(namespace, key_name, key_type, key_to_name, cast) do + defp cast_client(namespace, key_name, key_type, key_to_name, proxy_name, cast) do cast = case cast do {cast, _} -> cast cast -> cast @@ -115,17 +116,30 @@ defmodule Lkn.Core.Specs do arglistcl = [key_name|arglist] argtypes = [key_type|Enum.map(cast.fun.arguments, &(&1.type))] - quote do - unquote(cast_doc) - @spec unquote({name, [], argtypes}) :: :ok - def unquote({name, [], arglistcl}) do - GenServer.cast(unquote(key_to_name).(unquote(key_name)), - {unquote(namespace), {unquote(name), unquote(arglist)}}) - end + case proxy_name do + {:ok, {proxy_name, _}} -> + quote do + unquote(cast_doc) + @spec unquote({name, [], argtypes}) :: :ok + def unquote({name, [], arglistcl}) do + unquote(proxy_name).(unquote(key_name), + unquote(key_to_name).(unquote(key_name)), + {unquote(namespace), {unquote(name), unquote(arglist)}}) + end + end + _ -> + quote do + unquote(cast_doc) + @spec unquote({name, [], argtypes}) :: :ok + def unquote({name, [], arglistcl}) do + GenServer.cast(unquote(key_to_name).(unquote(key_name)), + {unquote(namespace), {unquote(name), unquote(arglist)}}) + end + end end end - defp call_client(namespace, key_name, key_type, key_to_name, call) do + defp call_client(namespace, key_name, key_type, key_to_name, proxy_name, call) do name = call.fun.name call_doc = if call.doc != :none do @@ -138,13 +152,26 @@ defmodule Lkn.Core.Specs do arglistcl = [key_name|arglist] argtypes = [key_type|Enum.map(call.fun.arguments, &(&1.type))] - quote do - unquote(call_doc) - @spec unquote({name, [], argtypes}) :: unquote(call.ret) - def unquote({name, [], arglistcl}) do - GenServer.call(unquote(key_to_name).(unquote(key_name)), - {unquote(namespace), {unquote(name), unquote(arglist)}}) - end + case proxy_name do + {:ok, {_, proxy_name}} -> + quote do + unquote(call_doc) + @spec unquote({name, [], argtypes}) :: unquote(call.ret) + def unquote({name, [], arglistcl}) do + unquote(proxy_name).(unquote(key_name), + unquote(key_to_name).(unquote(key_name)), + {unquote(namespace), {unquote(name), unquote(arglist)}}) + end + end + _ -> + quote do + unquote(call_doc) + @spec unquote({name, [], argtypes}) :: unquote(call.ret) + def unquote({name, [], arglistcl}) do + GenServer.call(unquote(key_to_name).(unquote(key_name)), + {unquote(namespace), {unquote(name), unquote(arglist)}}) + end + end end end diff --git a/lib/lkn/core/system.ex b/lib/lkn/core/system.ex index 50d3fc1..15420e3 100644 --- a/lib/lkn/core/system.ex +++ b/lib/lkn/core/system.ex @@ -236,6 +236,12 @@ defmodule Lkn.Core.System do key_to_name = quote do &(Lkn.Core.Name.system(&1, unquote(name))) end + proxy_cast = quote do + &(Lkn.Core.Instance.proxy_cast(&1, &2, &3)) + end + proxy_call = quote do + &(Lkn.Core.Instance.proxy_call(&1, &2, &3)) + end quote do defmodule unquote(name) do @@ -259,6 +265,7 @@ defmodule Lkn.Core.System do quote do unquote(Specs.var_name("map_key")) :: Lkn.Core.Map.k end, quote do unquote(Specs.var_name("puppets")) :: Lkn.Core.System.puppets end, ], + proxy_names: {proxy_cast, proxy_call} )) @doc false |