Comment on Mint's receive block

As an example for receiving messages return from Mint.HTTP.request/4, in the Mint manual from the official document at https://hexdocs.pm/mint/Mint.HTTP.html#content. it is written -

receive do
  message ->
    case Mint.HTTP.stream(conn, message) do
      :unknown -> handle_normal_message(message)
      {:ok, conn, responses} -> handle_responses(conn, responses)
    end
end

From this sample code, you can see that the receive block pulls off whatever the first message that is in the process’s message queue, and then it checks again the Mint.HTTP.stream/2 to see that the first message is of the right message type that is sent back to this process by issue the HTTP action. If it is not of the wanted type, it discards that message and then it continues to find the message from the remaining messages in the Process Message block queue.

As Erlang processes can receive messages from any other processes, I think that we should use a more specific pattern to match the exact pattern that could be returned from using Mint library, just to preserve the non-Mint’s messages in the front of the process memory block queue.

Some editions to the original message above as pointed out by @jwarlander in the comment below -

the messages that got fetched out of the queue didn’t get discarded, they are been sent to handle_normal_message(message) to handle those messages.

So to rephrase, What I want to point out here is that these messages that could not be handled by this mint’s receive block, should not be fetched out at the time of this receive block is called. And we can use another strict pattern to match what we want instead of matching to anything in front of the queue.

Well, no… It doesn’t discard the message. It gets passed to the handle_normal_message/1 function, as an example… This is where you’d implement any regular message handling of non-Mint messages.

thank your @jwarlander for correcting me.
Yes it is not discarded.

But at this time of using receive block, we would only want to handle mint’s related messages. We should preserve the other messages in the process memory block, and not fetch it out.

This is my intention of writing this post.

I have add some more info in the post above to be specific.


Dev.

Thanks for clarifying!

The given interface appears to solve for the most common needs, and helpfully abstracts away some of the underlying details.

I can see what you mean though, and in some cases indeed it would be helpful, but selective receive isn’t always a great default approach to go for – and if you truly need it, it doesn’t take too much digging to see what you’d need to match on (eg. what Mint.HTTP.stream/2 does behind the scenes)… probably something like:

receive do
  {tag, _, _} = msg when tag in [:tcp, :ssl, :tcp_error, :ssl_error] ->
    process_mint_message(msg)
  {tag, _} = msg when tag in [:tcp_closed, :ssl_closed] ->
    process_mint_message(msg)
end

Of course, it would be useful to include a pattern matching receive block in the docs as an example… perhaps you could do a pull request to see if it would be accepted?

@jwarlander thank you for showing this patterns.

I really think this above patterns should be the default.

As fetching of message from the queue goes, I really think that we should always selectively fetch the message that we can handle, not just fetch anything and then see if the message is what we wanted? if this message is not what we want then find the way to handle it.

Normally I think you would / should know what messages to expect, eg. those that relate to the purpose of your process. In this specific case, you could most often easily pattern-match any other messages you expect first, then pick it off and check if it’s a Mint message as the final case.

The problem with selective receive is that it can have a performance penalty if your mailbox has a lot of messages in it; also, you usually want a catch-all case somewhere in your main process loop to avoid message overflow.

For more in-depth info, see eg. https://www.erlang-solutions.com/blog/receiving-messages-in-elixir-or-a-few-things-you-need-to-know-in-order-to-avoid-performance-issues.html which is a good overview.

1 Like

Thank you @jwarlander

For updating about the drawbacks of using selective receive block also.

But as per document go I think selective receive block should be default on them. I have create an issue on the repository to see how maintainer think of it.

Thanks
Dev.