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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lud" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/120/14382_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lud
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>You are right that await infinity is not enough but I think I could just call <code>yield</code> again (after sending back “processing”) and this second time use shutdown (actually the form <code>yield(…) || shutdown(…)</code>).</p>
<p>That would allow to keep the <code>%Task{}</code> data structure opaque.</p>
<p>Of course I will not simply use <code>spawn</code> as I said before <img src="https://forum.elixirforum.com/images/emoji/apple/wink.png?v=15" title=":wink:" class="emoji" alt=":wink:" loading="lazy" width="20" height="20"></p>
<p>I think you demo lacks a layer of spawning though. <code>launch</code> must return in the 2500ms time frame, it can not return after “better late than ever”. At this point the application should use the other mean of sending results, and <code>launch</code> must have returned with a dummy value.</p>
<p>Thait is why I send messages manually.</p>
<p>Thank you very much for the code <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147358" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-147358" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147358"
                     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="147360" data-post-id="147360">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="lud" data-post="12" data-topic="26148">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/48/14382_2.png" class="avatar"> lud:</div>
<blockquote>
<p><code>launch</code> must return in the 2500ms time frame,</p>
</blockquote>
</aside>
<p><code>handle_task_yield</code> will run either after the result is delivered or after the first <code>@max_wait_ms</code> timeout expires - so it is there where you would be sending the “it’s going to be late” message.</p>
<p>Also consider that <em>depending on what a <code>GenServer</code> is doing</em> using <code>Task.yield</code> or <code>Task.await</code> directly may not be advisable. So you either have to spawn a separate vanilla process (with it’s own mailbox) or simply handle the <code>Task</code> messages via <code>handle_info</code> - in which case <code>%Task{}</code> can’t be treated as an opaque type.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147360" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-147360" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147360"
                     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="147365" data-post-id="147365">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lud" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/120/14382_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lud
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Sorry but I do not get it.</p>
<p>Imagine a task that will never finish for the example.</p>
<p><code>handle_task_yield</code> is called after <code>Task.yield</code>, which already waited <code>@max_wait_ms</code></p>
<p>If the arg to <code>handle_task_yield</code> is <code>nil</code>, it will call <code>await_late_result</code> and again wait <code>@max_wait_ms</code>.</p>
<p>So <code>launch</code> has not returned after the first timeout. The result is not delivered.</p>
<p>Thanks for your time <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>Edit: or your <code>IO.puts("Time out")</code> is actually my <code>send(parent, {:result, :still_running})</code> in which case we agree and that is what I will do, just using <code>yield</code> twice.</p>
<blockquote>
<p>using <code>Task.yield</code> or <code>Task.await</code> directly may not be advisable.</p>
</blockquote>
<p>This is why I used <code>send</code> : the parent expects one and only one message from the middle task layer (my <code>spawn</code>’ed process).</p>
<p>I will do a proper implementation soon and ask for your review if you do not mind.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147365" data-batch-url="/posts/batch_likers">
                        1
                      </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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-147365" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147365"
                     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="147378" data-post-id="147378">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>From the GenServer’s perspective the intermediate timeout doesn’t really serve any purpose - <em>unless it needs to let someone else know</em> - if it handles the tasks directly.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># file: my_app/lib/my_app/application.ex
#
# created with "mix new my_app --sup"
# 
defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    name = MyApp.TaskSupervisor

    children = [
      {Task.Supervisor, name: name},
      {Demo, name: name}
    ]

    opts = [strategy: :rest_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end
</code></pre>
<pre data-code-wrap="elixir"><code class="lang-elixir"># file: my_app/lib/demo.ex
#
defmodule Demo do
  use GenServer

  def start_link(args) do
    GenServer.start_link(__MODULE__, args, name: __MODULE__)
  end

  def init(args) do
    with {:ok, name} &lt;- Keyword.fetch(args, :name) do
      {:ok, {name, nil}}
    else
      _ -&gt;
        {:stop, :badarg}
    end
  end

  def handle_call({:launch, arg}, _from, {name, nil}) do
    handles = launch_task(name, arg)
    {:reply, :ok, {name, handles}}
  end

  def handle_info({:kill_task, mon}, {name, handles} = state) do
    # timeout expired
    case handles do
      {%Task{ref: ^mon} = task, _} -&gt;
        Process.demonitor(mon, [:flush])
        kill_task(task)
        IO.puts("Timed out: #{inspect(task)}")
        {:noreply, {name, nil}}

      _ -&gt;
        IO.puts("REDUNDANT timeout")
        {:noreply, {name, state}}
    end
  end

  def handle_info({:DOWN, mon, _, down_pid, reason}, {name, handles} = state) do
    # :DOWN message arrives when task exits
    case handles do
      {%Task{ref: ^mon} = task, timeout_ref} -&gt;
        Process.cancel_timer(timeout_ref)
        Process.demonitor(mon, [:flush])
        IO.puts("DOWN: #{inspect(down_pid)} #{inspect(reason)}")
        new_handles = if(reason == :normal, do: {task, nil}, else: nil)
        {:noreply, {name, new_handles}}

      _ -&gt;
        IO.puts("REDUNDANT DOWN: #{inspect(down_pid)} #{inspect(reason)}")
        {:noreply, {name, state}}
    end
  end

  def handle_info({mon, value}, {name, handles} = state) when is_reference(mon) do
    # normal task result arrives here - demonitor/flush :normal :DOWN
    case handles do
      {%Task{ref: ^mon}, timeout_ref} -&gt;
        if timeout_ref do
          Process.cancel_timer(timeout_ref)
          Process.demonitor(mon, [:flush])
        end

        IO.puts("result: #{inspect(value)}")
        {:noreply, {name, nil}}

      _ -&gt;
        IO.puts("REDUNDANT result: #{inspect(value)} with #{inspect(mon)}")
        {:noreply, state}
    end
  end

  def handle_info(msg, state) do
    IO.inspect(msg)
    {:noreply, state}
  end

  # ---

  @max_wait_ms 500
  @timely_timeout div(@max_wait_ms, 2)
  @too_late_timeout 3 * @max_wait_ms

  defp launch_task(name, arg) do
    %Task{ref: mon} = task = Task.Supervisor.async_nolink(name, __MODULE__, :some_work, [arg])
    ref = Process.send_after(self(), {:kill_task, mon}, @max_wait_ms)
    {task, ref}
  end

  defp kill_task(%Task{pid: pid}),
    do: Process.exit(pid, :kill)

  def some_work(:timely = type) do
    Process.sleep(@timely_timeout)
    type
  end

  def some_work(:too_late = type) do
    Process.sleep(@too_late_timeout)
    type
  end

  def some_work(:crash = type) do
    Process.sleep(@timely_timeout)
    exit(type)
  end

  def some_work(:too_late_crash = type) do
    Process.sleep(@too_late_timeout)
    exit(type)
  end

  # --- Demo API ---

  def launch(arg),
    do: GenServer.call(__MODULE__, {:launch, arg})
end
</code></pre>
<pre><code class="lang-plaintext">$ iex -S mix
Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Compiling 1 file (.ex)
Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&gt; Demo.launch(:too_late)
:ok
iex(2)&gt; Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.148.0&gt;, ref: #Reference&lt;0.177062570.1582825475.5428&gt;}

nil
iex(3)&gt; Demo.launch(:crash)   
:ok
iex(4)&gt; 
14:13:26.156 [error] Task #PID&lt;0.151.0&gt; started from Demo terminating
** (stop) :crash
    (my_app) lib/demo.ex:105: Demo.some_work/1
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (elixir) lib/task/supervised.ex:35: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: &amp;Demo.some_work/1
    Args: [:crash]
DOWN: #PID&lt;0.151.0&gt; :crash

nil
iex(5)&gt; Demo.launch(:too_late_crash)
:ok
iex(6)&gt; Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.154.0&gt;, ref: #Reference&lt;0.177062570.1582825480.4596&gt;}

nil
iex(7)&gt; 
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
       (v)ersion (k)ill (D)b-tables (d)istribution
a
Peers-MBP:my_app wheatley$ mix format
Peers-MBP:my_app wheatley$ iex -S mix
Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Compiling 1 file (.ex)
Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&gt; Demo.launch(:timely)
:ok
iex(2)&gt; result: :timely

nil
iex(3)&gt; Demo.launch(:too_late) 
:ok
iex(4)&gt; Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.151.0&gt;, ref: #Reference&lt;0.981638884.3997958147.252725&gt;}

nil
iex(5)&gt; Demo.launch(:crash)
:ok
iex(6)&gt; 
14:15:12.347 [error] Task #PID&lt;0.154.0&gt; started from Demo terminating
** (stop) :crash
    (my_app) lib/demo.ex:105: Demo.some_work/1
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (elixir) lib/task/supervised.ex:35: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: &amp;Demo.some_work/1
    Args: [:crash]
DOWN: #PID&lt;0.154.0&gt; :crash

nil
iex(7)&gt; Demo.launch(:too_late_crash)
:ok
iex(8)&gt; Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.157.0&gt;, ref: #Reference&lt;0.981638884.3997958147.252801&gt;}

nil
iex(9)&gt; 
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147378" data-batch-url="/posts/batch_likers">
                        1
                      </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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-147378" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147378"
                     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 #14"></div>
  </section>
</div>
    <div class="postbit" id="147382" data-post-id="147382">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lud" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/120/14382_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lud
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here  <code>Demo.launch</code> does not return <code>:timely</code> but <code>:ok</code>. Either I cannot grasp what you are trying to show or you did not understand the problem correctly.</p>
<p>The <code>launch</code> function must return the task result if it completes in the timeframe. I need that:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">@spec launch(function, function) :: {:ok, result} | :still_running
  def launch(code_to_run, post_late_result)
      when is_function(code_to_run, 0) and is_function(post_late_result, 1) do
    # You need to run code_to_run and return its result within 2500ms

    # If the code is not finished after 2500ms, you must return
    # :still_running but the code must continue to run, and you must
    # call post_late_result/1 with the result.

    # Bonus points : If code_to_run crashes, it must be restarted and ran again.
  end
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147382" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-147382" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147382"
                     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 #15"></div>
  </section>
</div>
    <div class="postbit" id="147384" data-post-id="147384">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="lud" data-post="16" data-topic="26148">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/48/14382_2.png" class="avatar"> lud:</div>
<blockquote>
<p>Either I cannot grasp what you are trying to show or you did not understand the problem correctly.</p>
</blockquote>
</aside>
<p>A function can only return once (and on top of anything it is <em>blocking</em>). And that is doable.</p>
<p>But then there is this:</p>
<blockquote>
<p>but the code must continue to run, and you must call post_late_result/1 with the result.</p>
</blockquote>
<p>That is not the behaviour of a <em>function</em> - we are now talking about a <em>message</em> protocol between processes. You are essentially mixing two different types of abstractions that shouldn’t be mixed …</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147384" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-147384" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147384"
                     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 #16"></div>
  </section>
</div>
    <div class="postbit" id="147389" data-post-id="147389">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lud" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/120/14382_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lud
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>That is not the behaviour of a <em>function</em></p>
</blockquote>
<p>It is the bahaviour of any function that start a task though.</p>
<p>Anyway I have the answer to my original question and I know what problems I must think of with my implementation. I think we are done. Thank you <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147389" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-147389" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147389"
                     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 #17"></div>
  </section>
</div>
    <div class="postbit" id="147402" data-post-id="147402">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>How I <strong>wouldn’t</strong> do it.</p>
<p>The problem is that the same result is delivered via two separate channels</p>
<ul>
<li>as a function return value</li>
<li>as a message if it resolves late.</li>
</ul>
<p>From a maintenance perspective that’s a mess - a single channel of delivery should be enough.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># file: my_app/lib/demo.ex
#
defmodule Demo do
  use GenServer

  def start_link(args) do
    GenServer.start_link(__MODULE__, args, name: __MODULE__)
  end

  def init(args) do
    with {:ok, name} &lt;- Keyword.fetch(args, :name) do
      {:ok, {name, nil, nil, false}}
    else
      _ -&gt;
        {:stop, :badarg}
    end
  end

  def handle_call({:launch, arg}, from, {name, nil, nil, _}) do
    handles = launch_task(name, arg)
    {:noreply, {name, handles, from, false}}
  end

  @max_wait_ms 500

  def handle_info({:DOWN, mon, _, down_pid, reason}, {name, handles, reply_to, pending} = state) do
    # :DOWN message arrives when task exits
    case handles do
      {%Task{ref: ^mon} = task, timeout_ref} -&gt;
        Process.cancel_timer(timeout_ref)
        Process.demonitor(mon, [:flush])
        IO.puts("DOWN: #{inspect(down_pid)} #{inspect(reason)}")

        if(reason == :normal) do
          {:noreply, {name, {task, nil}, reply_to, pending}}
        else
          reply(reply_to, {:result, {:error, reason}}, pending)
          {:noreply, {name, nil, nil, nil}}
        end

      _ -&gt;
        IO.puts("REDUNDANT DOWN: #{inspect(down_pid)} #{inspect(reason)}")
        {:noreply, state}
    end
  end

  def handle_info({:pending_task, mon}, {name, handles, reply_to, pending} = state) do
    # first timeout expired
    case {handles, pending} do
      {{%Task{ref: ^mon} = task, _}, false} -&gt;
        ref = Process.send_after(self(), {:kill_task, mon}, @max_wait_ms)
        reply(reply_to, {:result, :pending}, pending)
        IO.puts("First time out: #{inspect(task)}")
        {:noreply, {name, {task, ref}, reply_to, true}}

      _ -&gt;
        IO.puts("REDUNDANT first timeout")
        {:noreply, state}
    end
  end

  def handle_info({:kill_task, mon}, {name, handles, reply_to, pending} = state) do
    # last timeout expired
    case handles do
      {%Task{ref: ^mon} = task, _} -&gt;
        Process.demonitor(mon, [:flush])
        kill_task(task)
        reply(reply_to, {:result, {:error, :timeout}}, pending)
        IO.puts("Timed out: #{inspect(task)}")
        {:noreply, {name, nil, nil, nil}}

      _ -&gt;
        IO.puts("REDUNDANT timeout")
        {:noreply, state}
    end
  end

  def handle_info({mon, value}, {name, handles, reply_to, pending} = state)
      when is_reference(mon) do
    # normal task result arrives here - demonitor/flush :normal :DOWN
    case handles do
      {%Task{ref: ^mon}, timeout_ref} -&gt;
        if timeout_ref do
          Process.cancel_timer(timeout_ref)
          Process.demonitor(mon, [:flush])
        end

        reply(reply_to, {:result, {:ok, value}}, pending)

        IO.puts("result: #{inspect(value)}")
        {:noreply, {name, nil, nil, nil}}

      _ -&gt;
        IO.puts("REDUNDANT result: #{inspect(value)} with #{inspect(mon)}")
        {:noreply, state}
    end
  end

  def handle_info(msg, state) do
    IO.inspect(msg)
    {:noreply, state}
  end

  defp reply(reply_to, reply, false),
    do: GenServer.reply(reply_to, reply)

  defp reply({pid, _}, reply, _),
    do: send(pid, reply)

  # ---

  @timely_timeout div(@max_wait_ms, 2)
  @late_timeout @max_wait_ms + @timely_timeout
  @too_late_timeout 3 * @max_wait_ms

  defp launch_task(name, arg) do
    %Task{ref: mon} = task = Task.Supervisor.async_nolink(name, __MODULE__, :some_work, [arg])
    ref = Process.send_after(self(), {:pending_task, mon}, @max_wait_ms)
    {task, ref}
  end

  defp kill_task(%Task{pid: pid}),
    do: Process.exit(pid, :kill)

  def some_work(:timely = type) do
    Process.sleep(@timely_timeout)
    type
  end

  def some_work(:late = type) do
    Process.sleep(@late_timeout)
    type
  end

  def some_work(:too_late = type) do
    Process.sleep(@too_late_timeout)
    type
  end

  def some_work(:crash = type) do
    Process.sleep(@timely_timeout)
    exit(type)
  end

  def some_work(:late_crash = type) do
    Process.sleep(@late_timeout)
    exit(type)
  end

  def some_work(:too_late_crash = type) do
    Process.sleep(@too_late_timeout)
    exit(type)
  end

  # --- Demo API ---

  def launch(arg) do
    {:result, result} = GenServer.call(__MODULE__, {:launch, arg})
    result
  end
end
</code></pre>
<pre><code class="lang-plaintext">$ iex -S mix
Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Compiling 1 file (.ex)
Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&gt; Demo.launch(:timely)
result: :timely
{:ok, :timely}
iex(2)&gt; Demo.launch(:late)  
:pending
iex(3)&gt; First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.150.0&gt;, ref: #Reference&lt;0.3242099791.3754688513.92878&gt;}
result: :late
flush
{:result, {:ok, :late}}
:ok
iex(4)&gt; Demo.launch(:too_late)
First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.153.0&gt;, ref: #Reference&lt;0.3242099791.3754688516.94279&gt;}
:pending
iex(5)&gt; Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.153.0&gt;, ref: #Reference&lt;0.3242099791.3754688516.94279&gt;}
flush
{:result, {:error, :timeout}}
:ok
iex(6)&gt; Demo.launch(:crash)   

16:51:58.678 [error] Task #PID&lt;0.156.0&gt; started from Demo terminating
** (stop) :crash
    (my_app) lib/demo.ex:142: Demo.some_work/1
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (elixir) lib/task/supervised.ex:35: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: &amp;Demo.some_work/1
    Args: [:crash]
DOWN: #PID&lt;0.156.0&gt; :crash
{:error, :crash}
iex(7)&gt; Demo.launch(:late_crash)
First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.158.0&gt;, ref: #Reference&lt;0.3242099791.3754688516.94341&gt;}
:pending
iex(8)&gt; 
16:52:10.607 [error] Task #PID&lt;0.158.0&gt; started from Demo terminating
** (stop) :late_crash
    (my_app) lib/demo.ex:147: Demo.some_work/1
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (elixir) lib/task/supervised.ex:35: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: &amp;Demo.some_work/1
    Args: [:late_crash]
DOWN: #PID&lt;0.158.0&gt; :late_crash
flush
{:result, {:error, :late_crash}}
:ok
iex(9)&gt; Demo.launch(:too_late_crash)
First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.161.0&gt;, ref: #Reference&lt;0.3242099791.3754688516.94370&gt;}
:pending
iex(10)&gt; Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.161.0&gt;, ref: #Reference&lt;0.3242099791.3754688516.94370&gt;}
flush
{:result, {:error, :timeout}}
:ok
iex(11)&gt; 
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147402" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-147402" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147402"
                     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 #18"></div>
  </section>
</div>
    <div class="postbit" id="147403" data-post-id="147403">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Better, cleaner.</p>
<p>Deliver result(s) only one way - as a message.</p>
<p>The initial function call returns <code>:ok</code> to indicate that the request was accepted.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># file: my_app/lib/demo.ex
#
defmodule Demo do
  use GenServer

  def start_link(args) do
    GenServer.start_link(__MODULE__, args, name: __MODULE__)
  end

  def init(args) do
    with {:ok, name} &lt;- Keyword.fetch(args, :name) do
      {:ok, {name, nil, nil}}
    else
      _ -&gt;
        {:stop, :badarg}
    end
  end

  def handle_call({:launch, arg}, from, {name, nil, nil}) do
    handles = launch_task(name, arg)
    {:reply, :ok, {name, handles, from}}
  end

  @max_wait_ms 500

  def handle_info({:DOWN, mon, _, down_pid, reason}, {name, handles, reply_to} = state) do
    # :DOWN message arrives when task exits
    case handles do
      {%Task{ref: ^mon} = task, timeout_ref} -&gt;
        Process.cancel_timer(timeout_ref)
        Process.demonitor(mon, [:flush])
        IO.puts("DOWN: #{inspect(down_pid)} #{inspect(reason)}")

        if(reason == :normal) do
          {:noreply, {name, {task, nil}, reply_to}}
        else
          reply(reply_to, {:result, {:error, reason}})
          {:noreply, {name, nil, nil}}
        end

      _ -&gt;
        IO.puts("REDUNDANT DOWN: #{inspect(down_pid)} #{inspect(reason)}")
        {:noreply, state}
    end
  end

  def handle_info({:pending_task, mon}, {name, handles, reply_to} = state) do
    # first timeout expired
    case handles do
      {%Task{ref: ^mon} = task, _} -&gt;
        ref = Process.send_after(self(), {:kill_task, mon}, @max_wait_ms)
        reply(reply_to, {:result, :pending})
        IO.puts("First time out: #{inspect(task)}")
        {:noreply, {name, {task, ref}, reply_to}}

      _ -&gt;
        IO.puts("REDUNDANT first timeout")
        {:noreply, state}
    end
  end

  def handle_info({:kill_task, mon}, {name, handles, reply_to} = state) do
    # last timeout expired
    case handles do
      {%Task{ref: ^mon} = task, _} -&gt;
        Process.demonitor(mon, [:flush])
        kill_task(task)
        reply(reply_to, {:result, {:error, :timeout}})
        IO.puts("Timed out: #{inspect(task)}")
        {:noreply, {name, nil, nil}}

      _ -&gt;
        IO.puts("REDUNDANT timeout")
        {:noreply, state}
    end
  end

  def handle_info({mon, value}, {name, handles, reply_to} = state)
      when is_reference(mon) do
    # normal task result arrives here - demonitor/flush :normal :DOWN
    case handles do
      {%Task{ref: ^mon}, timeout_ref} -&gt;
        if timeout_ref do
          Process.cancel_timer(timeout_ref)
          Process.demonitor(mon, [:flush])
        end

        reply(reply_to, {:result, {:ok, value}})

        IO.puts("result: #{inspect(value)}")
        {:noreply, {name, nil, nil}}

      _ -&gt;
        IO.puts("REDUNDANT result: #{inspect(value)} with #{inspect(mon)}")
        {:noreply, state}
    end
  end

  def handle_info(msg, state) do
    IO.inspect(msg)
    {:noreply, state}
  end

  defp reply({pid, _}, reply),
    do: send(pid, reply)

  # ---

  @timely_timeout div(@max_wait_ms, 2)
  @late_timeout @max_wait_ms + @timely_timeout
  @too_late_timeout 3 * @max_wait_ms

  defp launch_task(name, arg) do
    %Task{ref: mon} = task = Task.Supervisor.async_nolink(name, __MODULE__, :some_work, [arg])
    ref = Process.send_after(self(), {:pending_task, mon}, @max_wait_ms)
    {task, ref}
  end

  defp kill_task(%Task{pid: pid}),
    do: Process.exit(pid, :kill)

  def some_work(:timely = type) do
    Process.sleep(@timely_timeout)
    type
  end

  def some_work(:late = type) do
    Process.sleep(@late_timeout)
    type
  end

  def some_work(:too_late = type) do
    Process.sleep(@too_late_timeout)
    type
  end

  def some_work(:crash = type) do
    Process.sleep(@timely_timeout)
    exit(type)
  end

  def some_work(:late_crash = type) do
    Process.sleep(@late_timeout)
    exit(type)
  end

  def some_work(:too_late_crash = type) do
    Process.sleep(@too_late_timeout)
    exit(type)
  end

  # --- Demo API ---

  def launch(arg),
    do: GenServer.call(__MODULE__, {:launch, arg})
end
</code></pre>
<pre><code class="lang-plaintext">$ iex -S mix
Erlang/OTP 22 [erts-10.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]

Compiling 1 file (.ex)
Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)&gt; Demo.launch(:timely)
:ok
iex(2)&gt; result: :timely
flush
{:result, {:ok, :timely}}
:ok
iex(3)&gt; Demo.launch(:late)  
:ok
iex(4)&gt; First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.151.0&gt;, ref: #Reference&lt;0.20248824.1341128709.106775&gt;}
result: :late
flush
{:result, :pending}
{:result, {:ok, :late}}
:ok
iex(5)&gt; Demo.launch(:too_late)
:ok
iex(6)&gt; First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.154.0&gt;, ref: #Reference&lt;0.20248824.1341128709.106808&gt;}
Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.154.0&gt;, ref: #Reference&lt;0.20248824.1341128709.106808&gt;}
flush
{:result, :pending}
{:result, {:error, :timeout}}
:ok
iex(7)&gt; Demo.launch(:crash)   
:ok
iex(8)&gt; 
17:08:54.993 [error] Task #PID&lt;0.157.0&gt; started from Demo terminating
** (stop) :crash
    (my_app) lib/demo.ex:139: Demo.some_work/1
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (elixir) lib/task/supervised.ex:35: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: &amp;Demo.some_work/1
    Args: [:crash]
DOWN: #PID&lt;0.157.0&gt; :crash
flush
{:result, {:error, :crash}}
:ok
iex(9)&gt; Demo.launch(:late_crash)
:ok
iex(10)&gt; First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.160.0&gt;, ref: #Reference&lt;0.20248824.1341128711.105922&gt;}
DOWN: #PID&lt;0.160.0&gt; :late_crash

17:09:09.046 [error] Task #PID&lt;0.160.0&gt; started from Demo terminating
** (stop) :late_crash
    (my_app) lib/demo.ex:144: Demo.some_work/1
    (elixir) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
    (elixir) lib/task/supervised.ex:35: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: &amp;Demo.some_work/1
    Args: [:late_crash]
flush
{:result, :pending}
{:result, {:error, :late_crash}}
:ok
iex(11)&gt; Demo.launch(:too_late_crash)
:ok
iex(12)&gt; First time out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.163.0&gt;, ref: #Reference&lt;0.20248824.1341128709.106905&gt;}
Timed out: %Task{owner: #PID&lt;0.145.0&gt;, pid: #PID&lt;0.163.0&gt;, ref: #Reference&lt;0.20248824.1341128709.106905&gt;}
flush
{:result, :pending}
{:result, {:error, :timeout}}
:ok
iex(13)&gt; 
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147403" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-147403" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147403"
                     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 #19"></div>
  </section>
</div>
    <div class="postbit" id="147411" data-post-id="147411">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="lud" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lud/120/14382_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  lud
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I agree with you but:</p>
<ul>
<li>There <em>are</em> two channels. This is not my design and I have to implement it.</li>
<li>You cannot send the late reply to the <code>from</code> of the initial call. It is a phoenix controller, after 2500ms it replies to the http request and then it’s gone. That is why there is another channel to send the late reply.</li>
</ul>
<p>Again I agree.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="147411" 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/should-i-call-task-await-if-task-yield-returns-ok-value/26148/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-147411" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="147411"
                     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 #20"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/26148/load_more?page=3">Load more posts (2 remaining)</a>
</div></template></turbo-stream>