vrod

vrod

I am wondering for advice on how to monitor an application with many genservers doing long-running work. Often we want to know “how many messages are in the queue?” The process has a mailbox not a queue but this is the same idea : how can we see what our app is doing? I have seen GenStage.estimate_buffered_count/2 and I am wondering if that is the best way. There is a mix of genserver and genstage, so I thought maybe Process.info/1 could help with genservers, but I noticed that this function seems to require a pid and it will not work with a process name. Also I do not see the messages in the process info? Only message_queue_len?
Another idea was because we are using pubsub, maybe we could add subscribers that would count messages but that feels maybe smelly.

Thank you for suggestions!

Showing Posts 1 to 10

RudManusachi

RudManusachi

To find a pid by process name we could check Process.whereis(:name)

And now we could see the messages via Process.info(pid, :messages), but only be careful, as this operation copies all messages to the process that called. So if mailbox is huge - the operation might be expensive.

mpope

mpope

A way to get all ‘monitor-able’ processes is to register them in a process group under the :pg module at startup. Then you’ll have a list of pids to call Process.info/1 on.

:pg.join(:message_length_procs, self())

lud

lud

If you need to do that kind of stuff a general patter is to do the actual work in a side process of the gen server (a Task process managed by the gen server), while the gen server just accept messages and put them in a queue (with the :queue module). So you can do whaterver you want with the queue : inspect it, filter it, or use another queue with priorization, etc.

rvirding

rvirding

Creator of Erlang

A simple way of of finding the length of the message queue is Process.info(pid, :message_queue_len) which avoids copying the whole message queue. Only having :message)_queue_len in the default info is to NOT copy all the messages unless you explicitly request it.

12
Post #4
vrod

vrod OP

Thank you! These are helpful suggestions. I think I can make this work with Process.info(pid, :message_queue_len) – I will look at the :pg module and :queue module to help make a better solution

vrod

vrod OP

Now that I am trying to make this work a bit more, I am not finding success. I have tried to simplify this by starting a genserver and sending messages to it using send/2, but I never see messages and message_queue_len is always zero.

RudManusachi

RudManusachi

Could you please show the code you try?

Here is the simple example in iex shell:

iex(1)> Process.info(self, :message_queue_len)
{:message_queue_len, 0}
iex(2)> send(self, :hello)
:hello
iex(3)> Process.info(self, :message_queue_len)
{:message_queue_len, 1}
iex(4)> Process.info(self, :messages)
{:messages, [:hello]}
vrod

vrod OP

Using self() works – I tried something a little more complicated where I named a GenServer like this:

defmodule Genfoo.Application do
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
    children = [
      Supervisor.child_spec(
        {Genfoo.Thing, %{name: :thing1}},
        id: :thing1
      )
    ]

    opts = [strategy: :one_for_one, name: Genfoo.Supervisor]
    Supervisor.start_link(children, opts)
  end
end


defmodule Genfoo.Thing do
  @moduledoc false
  use GenServer

  def start_link(%{name: name} = state) do
    GenServer.start_link(__MODULE__, state, name: name)
  end

  @impl true
  def init(state) do
    {:ok, state}
  end

  @impl true
  def handle_info(_msg, state) do
    IO.puts("handle_info")
    {:noreply, state}
  end

  @impl true
  def handle_call(_msg, _from, state) do
    IO.puts("handle_call")
    {:reply, "Called", state}
  end

  @impl true
  def handle_cast(_msg, state) do
    IO.puts("handle_cast")
    {:noreply, state}
  end
end

Then I tried this:

pid = Process.whereis(:thing1)
send(pid, "xx")
:thing1 |> Process.whereis() |> Process.info(:messages)

Sorry I must be doing something wrong. I expected to be able to inspect the named genserver process.

RudManusachi

RudManusachi

As soon as your process successfully fetches the message from mailbox (which it does in your handle_info) - it’s not there anymore. As a result your mailbox gets emptied out pretty fast =)


to continue showing in the simple example in iex

iex(1)> Process.info(self, :message_queue_len)
{:message_queue_len, 0}
iex(2)> send(self, :hello)
:hello
iex(3)> Process.info(self, :message_queue_len)
{:message_queue_len, 1}
iex(4)> Process.info(self, :messages)
{:messages, [:hello]}

# fetch the first message from the message_queue
iex(5)> receive do
...(5)>   any_message -> any_message
...(5)> end
:hello

# now message_queue is empty
iex(6)> Process.info(self, :message_queue_len)
{:message_queue_len, 0}
iex(7)> Process.info(self, :messages)
{:messages, []}
vrod

vrod OP

I see. I guess I am not fully understanding how handle_info processes a message.
I added Process.sleep(5000) to handle_info and I think I understand how this works now.

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews