sezaru

sezaru

Hello,

Setting the timeout value in my GenServer calls was always something that I found uncomfortable, it seemed to me that 5 seconds default was kinda a “random” number and I was not sure what number I needed to use.

At the same time, I was scared of using :infinity for it since you rarely see an example using it, so I thought it was not safe (I thought you would be stuck if the callee died or something like that).

Well, looking deeply I found this link Thoughts on when to use ‘infinity’ timeouts for gen_server:call and friends. They do discuss the call default timeout and says that it should be :infinity by default.

After that, I did some tests and indeed it seems to me to be very safe to use it as the default (and only use a timed timeout when it really makes sense). It fixed a lot of issues I had with timeouts when I changed the backend machine processing power which would often trigger these timeouts.

So, my question is a two-part one (sorry for that), the first part is, what is your opinion about that? Maybe Genserver documentation should be more clear about it (If it is I couldn’t find it sincerely)? Maybe we should have :infinity as the default timeout for calls as the link suggests?

The second part of the question is in regard of other timeouts configurations in the system that too are not really clear if they are safe to use :infinity or not.

For example, Ecto.Repo, you have the :timeout parameter for your config, this is what the documentation tells about it:

The time in milliseconds to wait for the query call to finish. :infinity will wait indefinitely (default: 15000)

As you can see, it mentions :infinity, but it is not clear (at least to me) if the query call is a Genserver.call or it is the call to the database server. If it is the first, I would consider safe to use :infinity since if the callee dies, we will not be stuck. But if it is referencing the database server, then my guess is that it could simply crash/disappear/whatever and it would never return from it, basically being locked in this call forever.

So, the second part of my question is, is it safe to use :infinity for the case of Ecto.Repo as an example? Do you know other libs that would not be?

Thank you very much.

Showing Posts 1 to 10

lucaong

lucaong

Indeed, in recent Elixir/Erlang versions, setting the GenServer call timeout to :infinity is a good default in my opinion: it is generally safe, does not depend on arbitrary timeouts, does not require special handling of messages that come late if the caller rescues failures, and can provide a back pressure mechanism in some cases. If the GenServer crashes, the caller will be notified, so it won’t be hanging forever. One case when it would hang though, is if your GenServer handles the call with a {:noreply, state} and then never sends a reply for whatever reason.

As for Ecto.Repo, I am personally not sure about the implication of the timeout.

asummers

asummers

IMO :infinity an an antipattern. It could be easily replaced with 3 hours and have the same effect. Should this run for 3h? Probably not. So why say it can run for infinity? If I have an Ecto query that has to e.g. take a whole table lock, and it can’t get the lock (say for TRUNCATE), giving it an infinity timeout will cause it to hold a DB worker forever. Get enough of these and you have major resource contention on your DB.

tiagodavi

tiagodavi

It makes sense.

sezaru

sezaru OP

I know what you mean, but at the same time, you are referring IMO to a specific situation, for that case you can consider a lower timeout because you want it to not lock something for too much time.

The point is that for the majority of the calls you would do, this would not be the case, and for that cases, it doesn’t seem to me that it makes sense to use anything but :infinity with the guarantees that @lucaong enumerated.

tiagodavi

tiagodavi

I needed to use :infinity in my tests because I was expecting a rabbitmq server returns. It works fine, but what @asummers said makes more sense.

asummers

asummers

If I have a single GenServer there’s only one message queue, so it exhibits the same resource contention as a DB. You can model this differently, of course, but naively using :infinity everywhere has the potential to deadlock your whole app. There are cases where you do need :infinity but I can’t think of any off the top of my head where saying 3 weeks or some equally silly large number would be less appropriate.

lucaong

lucaong

The thing is, speaking about asynchronous calls in general and not referring to GenServer, it makes sense to explicitly timeout when something takes more than reasonable. With GenServer though, if the call times out, the caller fails, but the server is still running and trying to produce the result even after the timeout. In other words, the deadlock would still be there, as the GenServer would be still blocked. If one really wants to free up resources when an operation takes too long, a custom timeout logic on the GenServer side is better than a timeout on the caller.

Conversely, using a timeout of :infinity would at least ensure that if there is an unreasonable delay, it surfaces immediately. The right action to take is then to enforce a timeout logic that cleans up resources, which is not what the GenServer.call/3 timeout does.

The GenServer timeout was absolutely necessary back when gen_server could crash without the caller knowing about that. Nowadays it’s generally not the case anymore.

sezaru

sezaru OP

That is a very good point that I was not aware of but it makes total sense if you think about it. The caller will be free but the callee would be still “locked/blocked” doing the job the caller requested.

sezaru

sezaru OP

When you say potential deadlock you mean when the caller calls the callee and the calle calls the caller back?

Yeah, I can see that you would get a deadlock forever, but at the same time I don’t see setting the timeout number to something big would help in this case, you would get this GenServer blocked for 3 weeks anyway until the timeout and then probably not too much time later a similar call would come that would block it again to more 3 weeks.

Personally I would consider this specific case as a software bug that needs to be fixed in the code side and not mitigated by timeout parameters.

shanesveller

shanesveller

I would actually say that IME :infinity timeouts have precisely the opposite effect. They obfuscate the problem because operations which can never succeed (in a reasonable time frame or not) do not result in local, actionable errors that can be handled at the calling site, logged, observed, or otherwise raised for human attention. They just result in deadlocks and upstream timeouts where someone else above you in the logical hierarchy chose not to use :infinity, perhaps at your load-balancing layer in the case of a web service.

The only way I can say :infinity helped me do discovery while understanding a problem was by providing a big red flag that I can search the codebase for to find the likely offender, which I assume is not how you meant this.

Where Next? Top

Trending in Questions Top

water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
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
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews