evbruno
Issue with Horde / HordeRegistry with elixir 1.18
Hi folks, I’m trying the simple SayHello example from the Horde docs, but I can’t get it to work.
I can start a child with:
Horde.DynamicSupervisor.start_child(
HelloClusterApp.HelloSupervisor,
{HelloClusterApp.SayHello, name: "say_hello_1"}
)
I can also lookup on both nodes, and the process is actually there:
iex(foo@jotumhein)> Horde.Registry.lookup(HelloClusterApp.HelloRegistry, "say_hello_1")
[{#PID<24805.479.0>, nil}]
and:
iex(bar@jotumhein)> Horde.Registry.lookup(HelloClusterApp.HelloRegistry, "say_hello_1")
[{#PID<0.479.0>, nil}]
But I can’t figure it out how to send a message.
I’m trying:
GenServer.call({:via, Horde.Registry, {HelloClusterApp.HelloRegistry, "say_hello_1"}}, :action)
.. but I always get this error (running on the same node or not):
** (exit) exited in: GenServer.call({:via, Horde.Registry, {HelloClusterApp.HelloRegistry, "say_hello_1"}}, :action, 5000)
** (EXIT) an exception was raised:
** (Protocol.UndefinedError) protocol String.Chars not implemented for type Tuple. This protocol is implemented for the following type(s): Atom, BitString, Date, DateTime, Float, Integer, List, NaiveDateTime, Time, URI, Version, Version.Requirement
Got value:
{#PID<0.219.0>, [:alias | #Reference<0.0.28035.3569112820.221577217.43273>]}
(elixir 1.18.4) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir 1.18.4) lib/string/chars.ex:22: String.Chars.to_string/1
(hello_cluster_app 0.1.0) lib/hello_cluster_app/say_hello.ex:37: HelloClusterApp.SayHello.handle_call/3
(stdlib 6.2.2.1) gen_server.erl:2381: :gen_server.try_handle_call/4
(stdlib 6.2.2.1) gen_server.erl:2410: :gen_server.handle_msg/6
(stdlib 6.2.2.1) proc_lib.erl:329: :proc_lib.init_p_do_apply/3
(elixir 1.18.4) lib/gen_server.ex:1128: GenServer.call/3
iex:13: (file)
11:58:14.039 [error] GenServer {HelloClusterApp.HelloRegistry, "say_hello_1"} terminating
** (Protocol.UndefinedError) protocol String.Chars not implemented for type Tuple. This protocol is implemented for the following type(s): Atom, BitString, Date, DateTime, Float, Integer, List, NaiveDateTime, Time, URI, Version, Version.Requirement
Got value:
{#PID<0.219.0>, [:alias | #Reference<0.0.28035.3569112820.221577217.43273>]}
(elixir 1.18.4) lib/string/chars.ex:3: String.Chars.impl_for!/1
(elixir 1.18.4) lib/string/chars.ex:22: String.Chars.to_string/1
(hello_cluster_app 0.1.0) lib/hello_cluster_app/say_hello.ex:37: HelloClusterApp.SayHello.handle_call/3
(stdlib 6.2.2.1) gen_server.erl:2381: :gen_server.try_handle_call/4
(stdlib 6.2.2.1) gen_server.erl:2410: :gen_server.handle_msg/6
(stdlib 6.2.2.1) proc_lib.erl:329: :proc_lib.init_p_do_apply/3
Last message (from #PID<0.219.0>): :action
State: %{count: 0, init_args: ["say_hello_1"]}
Client #PID<0.219.0> is alive
(stdlib 6.2.2.1) gen.erl:260: :gen.do_call/4
(elixir 1.18.4) lib/gen_server.ex:1125: GenServer.call/3
(elixir 1.18.4) src/elixir.erl:386: :elixir.eval_external_handler/3
(stdlib 6.2.2.1) erl_eval.erl:919: :erl_eval.do_apply/7
(elixir 1.18.4) src/elixir.erl:364: :elixir.eval_forms/4
(elixir 1.18.4) lib/module/parallel_checker.ex:120: Module.ParallelChecker.verify/1
(iex 1.18.4) lib/iex/evaluator.ex:336: IEx.Evaluator.eval_and_inspect/3
(iex 1.18.4) lib/iex/evaluator.ex:310: IEx.Evaluator.eval_and_inspect_parsed/3
Same thing if running with GenServer.call(HelloClusterApp.SayHello.via_tuple("say_hello_1"), :action)
Extra info
I have created a new project scaffold with mix new hello_cluster_app --sup, and my build is:
$ elixir -v
Erlang/OTP 27 [erts-15.2.7] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [dtrace]
Elixir 1.18.4 (compiled with Erlang/OTP 26)
application.ex starts as:
def start(_type, _args) do
topologies = [example: [strategy: Cluster.Strategy.Gossip]]
children = [
{Cluster.Supervisor, [topologies, [name: HelloClusterApp.ClusterSupervisor]]},
{Horde.Registry, [name: HelloClusterApp.HelloRegistry, keys: :unique, members: :auto]},
{Horde.DynamicSupervisor,
[name: HelloClusterApp.HelloSupervisor, strategy: :one_for_one, members: :auto]}
]
opts = [strategy: :one_for_one, name: HelloClusterApp.Supervisor]
Supervisor.start_link(children, opts)
end
say_hello.ex:
defmodule HelloClusterApp.SayHello do
use GenServer
require Logger
def child_spec(opts) do
name = Keyword.get(opts, :name, __MODULE__)
%{
id: "#{__MODULE__}_#{name}",
start: {__MODULE__, :start_link, [name]},
shutdown: 10_000,
restart: :transient
}
end
def start_link(name) do
case GenServer.start_link(__MODULE__, [name], name: via_tuple(name)) do
{:ok, pid} ->
{:ok, pid}
{:error, {:already_started, pid}} ->
Logger.info("already started at #{inspect(pid)}, returning :ignore")
:ignore
end
end
@impl true
def init(args) do
state = %{count: 0, init_args: args}
{:ok, state}
end
def via_tuple(name), do: {:via, Horde.Registry, {HelloClusterApp.HelloRegistry, name}}
@impl true
def handle_call(msg, from, state) do
IO.puts("Handling call: #{from} => #{inspect(state)} => #{inspect(msg)}")
{:reply, :foo, state}
end
@impl true
def handle_info(msg, state) do
IO.puts("Handling info: #{inspect(state)} => #{inspect(msg)}")
{:noreply, state}
end
end
Most Liked
evbruno
OMFG!
I wrote this last night while not fully awake and I missed that! shame on me!
Thank you so much!
ps: having a little of time to inspect the stack trace, the error message was clear and I didn’t pay enough attention to it:
(elixir 1.18.4) lib/string/chars.ex:22: String.Chars.to_string/1
---> (hello_cluster_app 0.1.0) lib/hello_cluster_app/say_hello.ex:37: HelloClusterApp.SayHello.handle_call/3
(stdlib 6.2.2.1) gen_server.erl:2381: :gen_server.try_handle_call/4
nerdyworm
Pretty sure you’ll just need to add an inspect(from) to your handle_call function:
IO.puts(“Handling call: #{from} => #{inspect(state)} => #{inspect(msg)}”)
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









