<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="167737" data-post-id="167737">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lucaong" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lucaong/120/21794_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lucaong
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Well, I understand that timeouts in general are a good thing, but the <code>GenServer.call</code> timeout gives you no chance of cleaning up, and hides the real problem.</p>
<p>Suppose we are in a scenario in which the <code>GenServer</code> operation is very slow. For the sake of the argument, let’s say it hangs forever. If the caller enforces a timeout with <code>GenServer.call/3</code>, even after the timeout elapses the <code>GenServer</code> is still hanging. Any subsequent call will be queued in the mailbox of the hanging <code>GenServer</code>, which keeps growing unbound. The real problem is not solved, because the <code>GenServer</code> is not released.</p>
<p>Using a timeout of <code>:infinity</code> would block the caller forever. It is also not a great course of action, but it reflects the real performance of the <code>GenServer</code>, propagating backpressure at least on that specific caller. I agree that it’s not the solution, but my point is that setting a timeout is not a solution either.</p>
<p>The real solution in such a case is a use-case specific timeout logic <em>inside</em> the <code>GenServer</code>, that knows how to cleanup resources.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="167737" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/case-to-use-or-not-use-infinity-as-timeout-for-calls/29949/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-167737" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="167737"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="167749" data-post-id="167749">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lucaong" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lucaong/120/21794_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lucaong
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here is a code example of what I mean. Let’s simulate a slow call (also printing a message every second while waiting):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Slow do
  def call(seconds) do
    for i &lt;- (1..seconds) do
      IO.puts("Waiting #{i}...")
      Process.sleep(1_000)
    end
  end
end
</code></pre>
<p>Now create a <code>GenServer</code> setting a 3 seconds call timeout:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule One do
  def start_link(), do: GenServer.start_link(__MODULE__, [], [])

  def hang(pid, seconds \\ 10),
    do: GenServer.call(pid, {:hang, seconds}, 3000)

  def init(_), do: {:ok, nil}

  def handle_call({:hang, seconds}, _from, state) do
    reply = Slow.call(seconds)
    {:reply, reply, state}
  end
end
</code></pre>
<p>If we call <code>One.hang(pid)</code>, it will hang until the 3 seconds timeout elapses, then error. As we can see from the printed messages though, the slow operation is still going on, and further calls will just engulf the inbox more and more:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:ok, pid} = One.start_link()

One.hang()
# Waiting 1...
# Waiting 2...
# Waiting 3...
# ** (exit) exited in: GenServer.call(#PID&lt;0.165.0&gt;, {:hang, 30}, 5000)
#     ** (EXIT) time out
#     (elixir) lib/gen_server.ex:1009: GenServer.call/3
# Waiting 4...
# Waiting 5...

One.hang()
# Waiting 6...
# Waiting 7...
# Waiting 8...
# ** (exit) exited in: GenServer.call(#PID&lt;0.165.0&gt;, {:hang, 30}, 5000)
#     ** (EXIT) time out
#     (elixir) lib/gen_server.ex:1009: GenServer.call/3
# Waiting 9...
# Waiting 10...
# Waiting 1...
# Waiting 2...
# Waiting 3...
</code></pre>
<p>The <code>GenServer.call</code> timeout is not really helping, as it only stops the <em>caller</em>, not the <em>callee</em>. What would work is to implement logic on the <em>callee</em> side to stop the slow operation and cleanup if a timeout elapses:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Two do
  def start_link(), do: GenServer.start_link(__MODULE__, [], [])

  def hang(pid, seconds \\ 10),
    do: GenServer.call(pid, {:hang, seconds}, :infinity)

  def init(_), do: {:ok, nil}

  def handle_call({:hang, seconds}, from, state) do
    task = Task.async(Slow, :call, [seconds])

    case Task.yield(task, 3000) || Task.shutdown(task) do
      {:ok, reply} -&gt; {:reply, reply, state}
      nil -&gt; {:stop, :timeout, state}
    end
  end
end
</code></pre>
<p>In this case, the slow call is wrapped in a <code>Task</code> that is terminated when the 3 seconds timeout elapses:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Two.hang(pid)
# Waiting 1...
# Waiting 2...
# Waiting 3...

# 18:57:12.341 [error] GenServer #PID&lt;0.165.0&gt; terminating
# ** (stop) time out
# Last message (from #PID&lt;0.104.0&gt;): {:hang, 30}
# ...
# ** (EXIT from #PID&lt;0.104.0&gt;) shell process exited with reason: time out
</code></pre>
<p>No more <code>"Waiting #..."</code> messages are logged, confirming that the slow <code>Task</code> is terminated after the timeout elapses.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="167749" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/case-to-use-or-not-use-infinity-as-timeout-for-calls/29949/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-167749" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="167749"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="167788" data-post-id="167788">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="jc00ke" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jc00ke/120/18365_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  jc00ke
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="sezaru" data-post="1" data-topic="29949">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sezaru/48/36113_2.png" class="avatar"> sezaru:</div>
<blockquote>
<p>So, the second part of my question is, is it safe to use <code>:infinity</code> for the case of <code>Ecto.Repo</code> as an example?</p>
</blockquote>
</aside>
<p>Just this week I had to switch some streaming queries to use <code>timeout: :infinity</code> because I was streaming several 100k CSV rows. Actually turned out Heroku couldn’t/won’t handle it (kept getting H18 errors) so I’m working on another solution. But I know I can’t get all the data out w/o using <code>:infinity</code>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="167788" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/case-to-use-or-not-use-infinity-as-timeout-for-calls/29949/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-167788" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="167788"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #13"></div>
  </section>
</div>
    <div class="postbit" id="167792" data-post-id="167792">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dimitarvp" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/120/38664_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dimitarvp
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I usually get annoyed by some longer-running requests to 3rd party API providers and just raise the timeout to 1 or 2 minutes and just pray that the callees (the GenServers) aren’t eternally waiting on a response long after the callers have timed out. I am usually extremely conservative and carefully study the timeout and cancellation options of the network services my apps work with. Take special care never to use <code>:infinity</code> there!</p>
<p>As <a class="mention" href="/u/lucaong" rel="nofollow">@lucaong</a> excellently demonstrated, the timeouts don’t do much for your application in general if the callees are deadlocked. So it’s best that you take special care that your GenServers will always eventually receive some kind of a response from the 3rd party service, even if it’s a failure. In that scenario I usually put anything between 5 to 120 seconds timeout in those GenServers and add 1-2 more seconds on top of that for my callers.</p>
<p>Haven’t worked on NASA-level projects yet <img src="https://forum.elixirforum.com/images/emoji/apple/smiley.png?v=15" title=":smiley:" class="emoji" alt=":smiley:" loading="lazy" width="20" height="20"> and can’t say how universally applicable such an approach is but I believe it’s a reasonable tradeoff.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="167792" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/case-to-use-or-not-use-infinity-as-timeout-for-calls/29949/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-167792" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="167792"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>