<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="150113" data-post-id="150113">
  <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>Just freehand but you may want to try something like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def task_fun(:store, event),
  do: store(event)

def task_fun(:publish, event),
  do: publish(event)

def run_tasks(event) do
  # blocks until list is reified
  # :max_concurrency defaults to System.schedulers_online/0
  MyApp.TaskSupervisor
  |&gt; Task.Supervisor.async_stream_nolink([:store, :publish], __MODULE__, :task_fun, [event], [])
  |&gt; Enum.to_list()
end

def handle_in(message, payload, socket) do
  event = build_event(message, payload, socket)
  # blocks until done
  run_tasks(event)
  {:reply, :ok, socket}
end
</code></pre>
<hr>
<p>And just <a href="https://hexdocs.pm/elixir/Task.html#await/2-compatibility-with-otp-behaviours" rel="noopener nofollow ugc">as reference</a> for the topic as a whole:</p>
<aside class="quote no-group">
<blockquote>
<p><strong>Compatibility with OTP behaviours</strong></p>
<p>It is not recommended to  <code>await</code>  a long-running task inside an OTP behaviour such as <a href="https://hexdocs.pm/elixir/GenServer.html" rel="noopener nofollow ugc"> <code>GenServer</code> </a>. Instead, you should match on the message coming from a task inside your <a href="https://hexdocs.pm/elixir/GenServer.html#c:handle_info/2" rel="noopener nofollow ugc"> <code>GenServer.handle_info/2</code> </a> callback. For more information on the format of the message, see the documentation for <a href="https://hexdocs.pm/elixir/Task.html#async/1" rel="noopener nofollow ugc"> <code>async/1</code> </a>.</p>
</blockquote>
</aside> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="150113" 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/task-start-vs-tasksupervisor/26718/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-150113" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="150113"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-solved cat-solved" title="Marked as solution"></div>
  </section>
</div>
    <div class="postbit" id="150126" data-post-id="150126">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="fxn" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/fxn/120/20274_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  fxn
                    <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>It is not recommended to  <code>await</code>  a long-running task inside an OTP behaviour such as <a href="https://hexdocs.pm/elixir/GenServer.html" rel="noopener nofollow ugc"> <code>GenServer</code>  </a>. Instead, you should match on the message coming from a task inside your <a href="https://hexdocs.pm/elixir/GenServer.html#c:handle_info/2" rel="noopener nofollow ugc"> <code>GenServer.handle_info/2</code>  </a>callback. For more information on the format of the message, see the documentation for <a href="https://hexdocs.pm/elixir/Task.html#async/1" rel="noopener nofollow ugc"> <code>async/1</code>  </a>.</p>
</blockquote>
<p>In this case, the WS stores to DynamoDB, and publishes to Kafka. Those are fast operations in normal circumstances.</p>
<p>Could you folks help me understand what could happen in the <code>Task.await/1</code> call in the original code?</p>
<p>The WS is not linked to the tasks because of the <code>async_nolink</code> call, but it still monitors them (the documentation of <code>async_nolink</code> does not say otherwise). Therefore, it receives exit signals from the task as messages. Channels <a href="https://hexdocs.pm/phoenix/Phoenix.Channel.html#c:handle_info/2" rel="noopener nofollow ugc">have a <code>handle_info</code> callback</a>, and it is not clear to me if <code>Task.await/1</code> is correct in a Phoenix Channel at all because <a href="https://github.com/elixir-lang/elixir/blob/055526057ac9992cc1df87441357c4e56d45235d/lib/elixir/lib/task.ex#L592-L609" rel="noopener nofollow ugc">it enters a <code>receive</code> block</a> to consume messages directly from the process mailbox. What do you think?</p>
<p>On the other hand, <code>Task.await/1</code> emits exit signals from within that <code>receive</code> block, whose origin is the WS process itself. How is the supervisor of the WS going to react to those signals? Is this why it has been said in the thread that <code>Task.await/1</code> would still need a <code>rescue</code> if I want the WS to not exit at all due to failures in those operations?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="150126" 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/task-start-vs-tasksupervisor/26718/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-150126" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="150126"
                     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="150128" data-post-id="150128">
  <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="fxn" data-post="14" data-topic="26718">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/fxn/48/20274_2.png" class="avatar"> fxn:</div>
<blockquote>
<p>Could you folks help me understand what could happen in the <code>Task.await/1</code> call in the original code?</p>
</blockquote>
</aside>
<p><a href="https://github.com/elixir-lang/elixir/blob/v1.9.4/lib/elixir/lib/task.ex#L602-L603" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/elixir-lang/elixir/blob/v1.9.4/lib/elixir/lib/task.ex#L602-L603</a></p>
<p><a href="https://hexdocs.pm/elixir/Kernel.html#exit/1" rel="noopener nofollow ugc"><code>Kernel.exit/1</code></a></p>
<p>See also:</p><aside class="quote quote-modified" data-post="3" data-topic="16439">
  <div class="title">
    <div class="quote-controls"></div>
    <img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/peerreynders/48/5826_2.png" class="avatar">
    <div class="quote-title__text-content">
      <a href="https://forum.elixirforum.com/t/can-you-rescue-catch-process-exits-in-a-task/16439/3" rel="nofollow">Can you rescue/catch process exits in a Task?</a> <a class="badge-category__wrapper " href="/c/questions-help/questions/53" rel="nofollow"><span data-category-id="53" style="--category-badge-color: #C14BFB; --category-badge-text-color: #000000; --parent-category-badge-color: #C14BFB;" data-parent-category-id="171" data-drop-close="true" class="badge-category --style-square --has-parent" title="Elixir Questions / Help"><span class="badge-category__name">Questions</span></span></a>
    </div>
  </div>
  <blockquote>
    It’s a bit more complicated than that: 
defmodule Demo do

  def run(arg) do
    try do
      result = do_it(arg)
      IO.puts("Value from local return #{inspect result}")

    rescue
      e in ArgumentError -&gt;
        IO.puts("An Argument error occured #{inspect e}")
        # Look at Kernel.defexception/1 and the Exception behaviour

    catch
      :exit, {:error, msg} -&gt;
        IO.puts("Exit from a called function: #{msg}")
        # BUT a callee inside the same process can decide to
    …
  </blockquote>
</aside>

<p><a href="https://hexdocs.pm/elixir/Kernel.html#raise/1" rel="noopener nofollow ugc"><code>Kernel.raise/1</code></a> is an Elixir style exception - <a href="http://erlang.org/doc/man/erlang.html#exit-1" rel="nofollow"><code>exit/1</code></a> is the original Erlang style process exception which can be caught within the process but will terminate that process if it is not caught.</p>
<hr>
<blockquote>
<p>Therefore, it receives exit signals from the task as messages.</p>
</blockquote>
<p>Signals relate to process links (and convert to <code>:EXIT</code> messages when trapped) - <code>:DOWN</code> messages relate to monitors - two entirely separate mechanisms.</p>
<hr>
<blockquote>
<p>it is not clear to me if  <code>Task.await/1</code>  is correct in a Phoenix Channel at all because <a href="https://github.com/elixir-lang/elixir/blob/055526057ac9992cc1df87441357c4e56d45235d/lib/elixir/lib/task.ex#L592-L609" rel="noopener nofollow ugc">it enters a  <code>receive</code>  block</a> to consume messages directly from the process mailbox. What do you think?</p>
</blockquote>
<p>That is the fundamental issue with <code>await</code> - it blocks the process outside of the OTP code. But keep in mind that even calls with <a href="https://hexdocs.pm/elixir/GenServer.html#call/3" rel="noopener nofollow ugc"><code>GenServer.call/3</code></a> to another process are blocking. So there are situations where it can be OK - it’s more of an issue of awareness of blocking behaviour.</p>
<hr>
<blockquote>
<p>On the other hand,  <code>Task.await/1</code>  emits exit signals from within that  <code>receive</code>  block</p>
</blockquote>
<p>Your channel/topic process is executing <code>await/2</code> and therefore <code>exit/1</code> - so it’s not a signal yet - it can still be stopped with a <code>try..catch</code>.</p>
<hr>
<blockquote>
<p>How is the supervisor of the WS going to react to those signals?</p>
</blockquote>
<p>If uncaught the channel/topic process will be terminated. I’m not sure how the supervisor is configured, so I can’t predict its behaviour.</p>
<hr>
<p>Further update:</p>
<p><a href="https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/channel.ex#L407-L414" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/channel.ex#L407-L414</a></p>
<p>So by default the channel/topic process won’t be restarted (from the server end) - “any termination (even abnormal) is considered successful”.</p>
<p><a href="https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/socket/pool_supervisor.ex#L42-L58" class="onebox" target="_blank" rel="noopener nofollow ugc">https://github.com/phoenixframework/phoenix/blob/master/lib/phoenix/socket/pool_supervisor.ex#L42-L58</a></p>
<p>And if I’m reading this right the supervisor is running <a href="https://hexdocs.pm/elixir/Supervisor.html#init/2-options" rel="noopener nofollow ugc">with default</a> <code>max_restarts:</code> (3) and <code>:max_seconds</code> (5) i.e. if there are more than 3 restarts within 5 seconds <a href="http://erlang.org/doc/design_principles/sup_princ.html#maximum-restart-intensity" rel="nofollow">the supervisor will terminate</a>.</p>
<p>So it looks like <em>intensely</em> crashing channel/topic processes will in fact terminate the pool supervisor easily.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="150128" 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/task-start-vs-tasksupervisor/26718/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-150128" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="150128"
                     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="150263" data-post-id="150263">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="fxn" data-post="6" data-topic="26718">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/fxn/48/20274_2.png" class="avatar"> fxn:</div>
<blockquote>
<p>I believe we lose the order guarantee, however.</p>
</blockquote>
</aside>
<p>So I would go with the current approach, where the channel is blocked. This means that actions on the client won’t receive a reply until the publishing is done - but other than that it is generally fine. I assume the publishing to the message bus is super fast, so that’s how I would roll honestly.</p>
<p>Or I would create a GenServer on every new channel with the purpose of keeping ordering. Every time you have to publish, you just cast the GenServer to do it for you. The GenServer would be started in its own supervisor (a DynamicSupervisor) and it would monitor the channel. Once the channel is DOWN, it exits.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="150263" 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/task-start-vs-tasksupervisor/26718/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-150263" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="150263"
                     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="150277" data-post-id="150277">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="fxn" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/fxn/120/20274_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  fxn
                    <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">
								<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="16" data-topic="26718">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/48/1787_2.png" class="avatar"> josevalim:</div>
<blockquote>
<p>So I would go with the current approach, where the channel is blocked. This means that actions on the client won’t receive a reply until the publishing is done - but other than that it is generally fine. I assume the publishing to the message bus is super fast, so that’s how I would roll honestly.</p>
</blockquote>
</aside>
<p>Agree.</p>
<p>To compare, I started to write an alternative with GenServer as you described. I had also a registry to be able to cast by name during the lifetime of the channel, and the solution based on <code>Task.Supervisor.async_stream_nolink/6</code> wins in simplicity.</p>
<p>The cost is less throghtput, but as a first implementation of this service I prefer to keep it simple first, and introduce the GenServer if usage shows it is justified. On the other side, the synchronous approach would allow us to send an ACK status back to the client (not a requirement right now, though).</p>
<p>Thanks man! <img src="https://forum.elixirforum.com/images/emoji/apple/heart.png?v=15" title=":heart:" class="emoji" alt=":heart:" 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="150277" 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/task-start-vs-tasksupervisor/26718/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-150277" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="150277"
                     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>