I have something similar to the following code:
genserver_name = "cool_name"
task = Task.async(fn -> MyModule.start() end)
:timer.sleep(500)
GenServer.cast(genserver_name, {:save, first_payload})
GenServer.cast(genserver_name, {:save, second_payload})
GenServer.cast(genserver_name, {:save, third_payload})
response = Task.await(task)
MyModule.start/0
is a normal function (MyModule
is not a GenServer) that starts a GenServer with the name of "cool_name"
(the name iss always different, but I don’t think this is important for the problem).
Additionally, after starting the GenServer, MyModule.start/0
is blocked and waits for the GenServer to receive messages from other processes. It checks the GenServer state every second with a GenServer.call
call and if it has the expected data, it unblocks and continues with processing it.
It normally receives the messages that update its state as expected in a few minutes, but I wanted to write a test for it, so I used the aforementioned code.
What I find strange is that if I remove the :timer.sleep/1
in the code above, the Task.await/1
times out and the GenServer.cast
calls don’t get called at all and the GenServer state is always empty, the MyModule.start/0
function checks it every second with a GenServer.call
and it is always empty. If I add the :timer.sleep/1
, it is empty, for instance, only on the first check, then the casts run, the state gets populated, and everything is fine, the Task.await/1
does not raise an exception.
I wonder what is the reason for this blocking without the :timer.sleep/1
and why the addition of the timer solves it. I’m guessing it has something to do with the GenServer.call
that checks the state every second, but I don’t think I can find the explanation with my current knowledge - it is called once every second and immediately returns the state (which in this case is just an empty map).
I am running this in an ExUnit test, but I think this is also not related to this specific issue.