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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="silverdr" data-post="11" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/silverdr/48/23771_2.png" class="avatar"> silverdr:</div>
<blockquote>
<p>but then the data is stored, and nothing knows what happens further with the job</p>
</blockquote>
</aside>
<p>This is the inherent problem with e-mails (or any distributed system for that matter). For example, a user might have mistyped their e-mail or the mail may have ended up in spam, or it has been filtered by some custom filter, and ultimately the user never sees the e-mail.</p>
<p>E-mail delivery is a “best effort” operation. You can only know that the user received it if they click on some unique link in that e-mail, which will lead to a request made to the site.</p>
<p>So we need to keep this property in mind and design the system accordingly. For example, if the e-mail is an activation e-mail, we’ll keep the user in the <code>activating</code> state until they click on the link, optionally removing or invalidating the user if they don’t active within some time-frame. That is indeed added complexity, but that complexity is inherent to the challenge. You can alternatively pretend that these issues don’t exist, and it might work mostly fine, but given enough time and users these problems will surface sooner or later.</p>
<aside class="quote no-group" data-username="silverdr" data-post="11" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/silverdr/48/23771_2.png" class="avatar"> silverdr:</div>
<blockquote>
<p>to local sendmail</p>
</blockquote>
</aside>
<p>Using a local mail server will certainly reduce the chances of something going wrong, but it won’t eliminate the problems completely. If the mail-server stops, or if it’s very busy, or if the rest of the system is very busy, you still might experience a scenario where an e-mail is enqueued and delivered, but the application gets an error and rolls the transaction back. See the “Application-level failures” in <a href="https://aphyr.com/posts/288-the-network-is-reliable" rel="noopener nofollow ugc">this article</a> for some real-world examples.</p>
<p>Beyond that, the issues mentioned by <a class="mention" href="/u/benwilson512" rel="nofollow">@benwilson512</a> still remain. You might send an e-mail successfully, but something may fail on the PostgreSQL side. To reduce the chance of this happening, you should strive to send the e-mail as the very last thing in the transaction, which is cumbersome and error-prone.</p>
<p>Ultimately, the naive approach increases the chances of e-mail being sent while the transaction is rolled back. I find this to be a serious issue, since we may end up misinforming the user (e.g. we tell the user that they have registered, while the database entry is in fact missing).</p>
<p>OTOH the persisted queue eliminates such possibility. Of course, this means you might end up saving something to the db while the e-mail is not sent, but as I already said, it’s always possible that the user won’t receive an e-mail, so you need to plan for such scenario anyway.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169361" data-batch-url="/posts/batch_likers">
                        3
                      </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/transactional-user-registration/30247/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-169361" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169361"
                     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="169369" data-post-id="169369">
  <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">
								<aside class="quote no-group quote-modified" data-username="sasajuric" data-post="9" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<aside class="quote no-group" data-username="dimitarvp" data-post="7" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<p>Do take special care. These 3rd party API calls (in your case, sending an email) must finish very quickly – 2s maximum.</p>
</blockquote>
</aside>
<p>This is basically impossible to guarantee. If the network is a bit slower, the network request might take longer. You could try to enforce some timeout, but that will increase the likelihood of the aforementioned scenario (mail is sent while the transaction is rolled back).</p>
</blockquote>
</aside>
<p>Oh, I am not saying it can be guaranteed and I fully agree with you and Ben that it’s a bad practice to pretend otherwise.</p>
<p>It’s just that for a lot of scenarios people can have some good probability of success and for the better or the worse, many devs go with that and get surprised in the future. <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>Didn’t know Oban can give those guarantees though, pretty good!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169369" 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/transactional-user-registration/30247/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-169369" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169369"
                     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="169372" data-post-id="169372">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="benwilson512" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/120/1457_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  benwilson512
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Craft GraphQL APIs in Elixir with Absinthe</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="silverdr" data-post="10" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/silverdr/48/23771_2.png" class="avatar"> silverdr:</div>
<blockquote>
<p>I asked for “best practice” suggestion so how would you suggest approaching this type of problem?</p>
</blockquote>
</aside>
<p>Sure. The ideal option is to use something like Oban which uses postgres as a queue, and then you can in a single transaction store the the user and a job which tracks that the email should be sent. The job could of course fail, but then it will be retried. All of the retries could fail, but then at least you have a record in the DB which lets you know that it failed so that you can fix the issue and try again later.</p>
<p>Really, the main scenario you want to avoid is that the email goes out BUT the user row doesn’t exist. Then someone tries to sign in with a user account that doesn’t exist.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169372" 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/transactional-user-registration/30247/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-169372" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169372"
                     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="169387" data-post-id="169387">
  <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>Yep, I second <a class="mention" href="/u/benwilson512" rel="nofollow">@benwilson512</a>’s suggestion. Using something like Oban to keep the job queues in the same database allows for atomically creating the record and scheduling the job. Also, it fails in ways that can be asserted (e.g. reaching a maximum number of retries) and leave a trail that can be inspected for manual intervention.</p>
<p>In case the job queues are not in the same DB, scheduling the job and creating the record cannot be done atomically. In one project where delivery is quite critical (not email in my case), we separated the problem:</p>
<ul>
<li>We make sure that the job queues are persistent, and that, once scheduled, a job cannot be lost.</li>
<li>After successfully scheduling the job, we mark a flag in the record. A check runs every few minutes to ensure that all records older than 1 minute successfully scheduled their job. If any record fails this check, an alert is triggered for manual inspection.</li>
<li>On the background workers side, we implemented a retry mechanism with backoff. If the maximum number of retries is reached, an alert is triggered and manual inspection is necessary.</li>
</ul>
<p>Basically, the whole idea was to have the system handling automatically the vast majority of cases, and alert in the very few exceptional cases that cannot be automatically recovered (but can be automatically asserted). Usually, it is also necessary to decide explicitly on the trade offs (like at-least-once vs. at-most-once delivery).</p>
<p>I would say that the “best practice” is, in general, to be aware of the possible failing modes, explicitly decide on the trade offs, and make sure that failures are minimized but also reported. How to do that in each specific case depends on the trade offs. <a class="mention" href="/u/benwilson512" rel="nofollow">@benwilson512</a>’s suggestion is probably the best way in the case presented in this thread.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169387" data-batch-url="/posts/batch_likers">
                        4
                      </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/transactional-user-registration/30247/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-169387" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169387"
                     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="169424" data-post-id="169424">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="silverdr" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/silverdr/120/23771_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  silverdr
                    <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 no-group" data-username="sasajuric" data-post="12" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>For example, a user might have mistyped their e-mail or the mail may have ended up in spam, or it has been filtered by some custom filter, and ultimately the user never sees the e-mail</p>
</blockquote>
</aside>
<p>Those are all cases I can possibly live with. If someone mistypes the email twice, sorry all bets are off. If my message landed in his spambox, sorry I can’t do anything about it either. Etc. The two cases I try to account for (as much as reasonably possible) is that only one of the two operations are executed successfully. Like I send the mail but there’s no account in the DB to be confirmed and the opposite - the account is created but mail is never sent (“sent” is what I care about, not “received” as this is out of scope here). There will always be some situations that I won’t be able to account for but that’s an “accept” type of risk resolution.</p>
<aside class="quote no-group" data-username="sasajuric" data-post="12" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>For example, if the e-mail is an activation e-mail, we’ll keep the user in the <code>activating</code> state until they click on the link, optionally removing or invalidating the user if they don’t active within some time-frame</p>
</blockquote>
</aside>
<p>That’s how I normally do it. I have an <code>activated_at</code> column, which remains NULL until the account is activated. The <code>created_at</code> is used for counting time before inactive accounts are removed.</p>
<aside class="quote no-group" data-username="benwilson512" data-post="14" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/48/1457_2.png" class="avatar"> benwilson512:</div>
<blockquote>
<p>Sure. The ideal option is to use something like Oban which uses postgres as a queue, and then you can in a single transaction store the the user and a job which tracks that the email should be sent. The job could of course fail, but then it will be retried. All of the retries could fail, but then at least you have a record in the DB which lets you know that it failed so that you can fix the issue and try again later.</p>
</blockquote>
</aside>
<p>As I mentioned, usually the local MTA did this for me (queueing, retrying, notifications, ..). I admit it may not always be the best approach but - in any case - whether this is User.transaction or something like <code>send_email! if user.save / rescue SendmailError</code> equivalent or any more sophisticated approach with Oban, the more Phoenix specific question from a noob in the Phoenix world is where would those who know better put the code handling these things?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169424" 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/transactional-user-registration/30247/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-169424" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169424"
                     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="169425" data-post-id="169425">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="silverdr" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/silverdr/120/23771_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  silverdr
                    <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 no-group" data-username="NobbZ" data-post="8" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/nobbz/48/27235_2.png" class="avatar"> NobbZ:</div>
<blockquote>
<p>Perhaps you can apply the “saga” pattern to come close to what you actually want?</p>
</blockquote>
</aside>
<p>It looks like the most robust thing, designed to handle such situations. But isn’t it a bit too heavy artillery for the so much typical case? How do you Phoenix experts handle it? Do you all use Oban or sage for registering users and sending activation token?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169425" 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/transactional-user-registration/30247/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-169425" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169425"
                     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="169426" data-post-id="169426">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="silverdr" data-post="16" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/silverdr/48/23771_2.png" class="avatar"> silverdr:</div>
<blockquote>
<p>Those are all cases I can possibly live with.</p>
</blockquote>
</aside>
<p>If the mail is not sent, then it is not received. If you can live with the case when the mail is not received, you can also live with the case when the mail is not sent. Hence this is not a problem:</p>
<blockquote>
<p>the account is created but mail is never sent</p>
</blockquote>
<p>While this is:</p>
<blockquote>
<p>I send the mail but there’s no account in the DB to be confirmed</p>
</blockquote>
<p>And thus the solution is to enqueue the job as a part of the db transaction, and then after the transaction is committed do the “best effort” of sending that e-mail, which means retrying to send for some reasonable amount of time.</p>
<p>OTOH if you insist on sending an e-mail inside the db transaction you won’t solve neither the first issue (an e-mail might still not be received, while the db record exists), nor the second one (an e-mail might be delivered but the db record is not present).</p>
<p>That’s all I have to say on the subject. Make of it what you will, and best of luck!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169426" data-batch-url="/posts/batch_likers">
                        5
                      </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/transactional-user-registration/30247/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-169426" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169426"
                     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="169462" data-post-id="169462">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="sasajuric" data-post="18" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>If the mail is not sent, then it is not received. If you can live with the case when the mail is not received, you can also live with the case when the mail is not sent. Hence this is not a problem:</p>
</blockquote>
</aside>
<p>It might result in the same outcome, but in terms of responsibilities/control it’s different. If I did successfully send the email off to a mail provider and something happens afterwards it’s out of my control. Me not successfully sending it off to the provider on the other hand is something I’m in control about and it’s therefore on my list of responsibilities.</p>
<p>To answer prev. questions: I feel saga’s are interesting in more high risk scenarios like e.g. external payment gateways and such things. They’re also not a good fit, as “email” doesn’t really have great compensation actions. If an email was sent there’s no turning back. You could send another mail “Sorry, something went wrong. Your user wasn’t created”, which seems sketchy at best.</p>
<p>Personally I feel using oban is a good middleground: You make sure queuing the email and creating the user is transactional, so once it comes to sending the email off you’re sure the pre-conditions were successful. So the only thing you have to deal with are errors …</p>
<ul>
<li>…, where your provider did already receive and send of the email. Usually sending a mail multiple times is ok(ish) and oban does retry.</li>
<li>…, where you got a success response, where there was an error. This really shouldn’t happen, but even if it does is not something in your control, but a problem with the provider. See the start of this post.</li>
</ul> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169462" 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/transactional-user-registration/30247/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-169462" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169462"
                     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="169686" data-post-id="169686">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="silverdr" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/silverdr/120/23771_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  silverdr
                    <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 no-group" data-username="LostKobrakai" data-post="19" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>It might result in the same outcome, but in terms of responsibilities/control it’s different. If I did successfully send the email off to a mail provider and something happens afterwards it’s out of my control. Me not successfully sending it off to the provider on the other hand is something I’m in control about and it’s therefore on my list of responsibilities.</p>
</blockquote>
</aside>
<p>Exactly!</p>
<aside class="quote no-group" data-username="sasajuric" data-post="18" data-topic="30247">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sasajuric/48/991_2.png" class="avatar"> sasajuric:</div>
<blockquote>
<p>OTOH if you insist on sending an e-mail inside the db transaction</p>
</blockquote>
</aside>
<p>I don’t insist on anything. I admit being out of my depth on both the language (which I certainly don’t “feel” currently yet) and the framework. My typical approach in “the other” language and framework was something like I quoted above:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">send_activation_email! if user.save 
[...]
rescue SendmailError =&gt; e
</code></pre>
<p>where I handle the unlikely situation of local error, while mail queueing, retrying, async error notification, etc. is handled by the MTA itself. Whether something like that is anywhere close to best practice/idiomatic approach in Phoenix world I have of course no idea. Hence my request for some light on how it is best/typically done in phx.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169686" 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/transactional-user-registration/30247/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-169686" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169686"
                     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="169745" data-post-id="169745">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Code like your example is likely the reason, why all those people in this thread warn you about the issues of not having transactional guarantees with external services. In elixir you can just as well do this, which is about the same as your example:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{:ok, user} = MyApp.Repo.insert(user)
case user |&gt; Email.registration |&gt; Mailer.deliver do
  :ok -&gt; :ok
  error -&gt; …
end
</code></pre>
<p>But as mentioned before this code no matter the language does have problems. For example saving the user could succeed, but the machine/service crashes before <code>Mailer.deliver</code> is called. I’m not sure what MTA means, but if it’s your mailing provider, there’s nothing for them to do about this. They can’t see the crash. In this specific case even your mailing library won’t help you, as even that wasn’t yet called.</p>
<p>Generally I feel in the elixir community there are many people of experience, which might have been burned by exactly such problems unlikely as one might imagine them. Given the beam and the ecosystem also provides a bunch of very nice tooling – like e.g. oban for persistent queues in most people’s default postgres db – which allows you to model the problem in a way, which acknowledges the issue of the task we tend do suggest using those instead of the straight forward, but problematic solution.</p>
<p>In this case a persistent queue – as mentioned before – makes the transaction of saving the user simpler and actually transactional (so in case of a crash you either have no user or a user and a persisted task for sending an email), while sending the email by executing the queue is the only place where you have to deal with the external service. Only here you’ll deal with timeouts, retrys and eventually stop trying if things keep failing. It’s still the same issues as without the persistent queue, but it’s separated from saving the user (doesn’t affect more code than it needs) and you’ll get a proper history of how many retrys you had, what the error(s) were and you can e.g. be notified if you need to manually resolve something. For the proposed problem in the start of this post nobody would even know that a mail wasn’t sent.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="169745" 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/transactional-user-registration/30247/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-169745" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="169745"
                     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/30247/load_more?page=3">Load more posts (1 remaining)</a>
</div></template></turbo-stream>