Cond doesnt get called inside receive function

Am trying to write a simple program to send messages successively to connected client but am facing a problem of condition being called only once

Code

defmodule Server do

  @interval 2000 #2 seconds
  @server_pid :server

  def start do
    pid = spawn(__MODULE__, :generate, [[]])
    :global.re_register_name(@server_pid, pid)
  end

  def register(client_id) do
    send :global.whereis_name(@server_pid), {:register, client_id}
  end

  def generate(clients) do
    receive do
      {:register, pid} ->
          IO.puts "registering #{inspect pid}"
        sender([pid|clients], 0)

      after @interval ->
        IO.puts "please add client"
        generate(clients)
    end
  end

  def sender(clients, currentPosition) do
    receive do
      {:register, pid} ->
          IO.puts "registering from sender #{inspect pid}"
          sender([pid|clients], currentPosition)

      after @interval ->
        IO.puts "Inside the looper position: #{currentPosition} length: #{inspect length(clients)} clients: #{inspect clients}"

        cond do
          length(clients) == 1 and currentPosition == 0 ->
          send Enum.at(clients, currentPosition), {:tick}
          sender(clients, currentPosition)

          length(clients) > 1 and currentPosition+ 1 != length(clients) ->
          send Enum.at(clients, currentPosition), {:tick}
          sender(clients, currentPosition + 1)

          length(clients) > 1 and currentPosition+ 1 == length(clients) ->
          send Enum.at(clients, currentPosition), {:tick}
          sender(clients, 0)
        end
    end
  end

end

defmodule Client do

  def start do
    pid = spawn(__MODULE__, :receiver, [])
    Server.register(pid)
  end

  def receiver do
    receive do
      {:tick} ->
      IO.puts "tock in client"
    end
  end

end

Any help is appreciated
Regards

There’s a number of issues in your code.

Your client process (receiver) will receive only one tick, then die.

Your server process (generate) will receive one register message, then block waiting for another one in the sender function, which AFAICT will never be sent.

You are using receive timeouts in a weird way - every two seconds your sender function will call itself, because it timeouts waiting for a register method.

I’m fairly sure the thing you want to accomplish would be better served with a GenServer. If you state what you are trying to do, we might be able to help.

1 Like

Hi @orestis
Thank you for your reply :grin:

I had not noticed I was not calling receiver again after receiving the {:tick} inside the client.

After making the changes on Client, the application is working as expected.

Am reading a book called Programming Elixir and I was required to write that program without genServer

Here is the question

Alter the code so that successive ticks are sent to each registered client
(so the first goes to the first client, the second to the next client, and so
on). Once the last client receives a tick, the process starts back at the
first. The solution should deal with new clients being added at any time.

solutions from other readers

Am going to read GenServer next and create that program using it.

Thank you again for suggesting that helpful tip :grinning: