aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Letan <contact@thomasletan.fr>2018-05-01 23:02:24 +0200
committerThomas Letan <contact@thomasletan.fr>2018-05-01 23:02:24 +0200
commitd4f61d0f54ba171c9716d59cdb1e7c6f9cd48a41 (patch)
tree3b99074485e9de97f0dd35e9de8df868588b3b0f
parentrelease: 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.ex20
-rw-r--r--lib/lkn/core/specs.ex65
-rw-r--r--lib/lkn/core/system.ex7
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