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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="outlog" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  outlog
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jaimeiniesta" data-post="41" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jaimeiniesta/48/1063_2.png" class="avatar"> jaimeiniesta:</div>
<blockquote>
<p>1.- Avoiding duplicate jobs. That is, being able to check if a job has already been enqueued with the same arguments so I can avoid enqueueing it twice.</p>
</blockquote>
</aside>
<p>or “named” jobs eg “send_email_for_bill_id:777” which of course should balk at duplicates<br>
(but haven’t thoroughly checked Oban out yet..)</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="130971" 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/oban-reliable-and-observable-job-processing/22449/42">Post #41</a>
	                </div>
	            </div>
              <div id="likers-container-130971" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="130971"
                     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 #41"></div>
  </section>
</div>
    <div class="postbit" id="130985" data-post-id="130985">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>That can be useful as well, but of course the API needs to be flexible - in many cases it’s totally fine to repeat past jobs with the same arguments, in other cases it may be fine to repeat a job that has already finished, in cases like sending emails for bills it’s probably not… In my case I only want to check that a job is not already waiting at the queue.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="130985" 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/oban-reliable-and-observable-job-processing/22449/43">Post #42</a>
	                </div>
	            </div>
              <div id="likers-container-130985" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="130985"
                     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 #42"></div>
  </section>
</div>
    <div class="postbit" id="130994" data-post-id="130994">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sorentwo" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sorentwo/120/37360_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sorentwo
                    <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 class="user-title">
									<span>Oban Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="jaimeiniesta" data-post="41" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jaimeiniesta/48/1063_2.png" class="avatar"> jaimeiniesta:</div>
<blockquote>
<p>Avoiding duplicate jobs. That is, being able to check if a job has already been enqueued with the same arguments so I can avoid enqueueing it twice.</p>
</blockquote>
</aside>
<p>This can definitely be achieved in Oban. Unlike Exq (or most any of the other libraries) you have complete control over how your jobs are inserted into the database.</p>
<p>First, a quick definition of “unique jobs” because in my experience the meaning can be confusing. Usually the uniqueness only applies to jobs that are in the queue. That means you can prevent putting two jobs with the same arguments in the queue <em>at the same time</em>, but it doesn’t prevent multiple jobs with the same arguments within <em>a window of time</em>. You mentioned this difference below, but I wanted to call it out for anybody that may not be familiar with the feature.</p>
<p>Here are some ways I can think of to implement unique jobs with different types of guarantees.</p>
<h4><a name="p-130994-h-1-partial-index-1" class="anchor" href="#p-130994-h-1-partial-index-1" aria-label="Heading link" rel="nofollow"></a>1. Partial Index</h4>
<p>Add an index for the worker that you want to enforce uniqueness for:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">create index(
  :oban_jobs,
  [:worker, :args],
  unique: true,
  where: "worker = 'MyApp.Worker' and state in ('available', 'scheduled')"
)
</code></pre>
<p>Then, pass <code>on_conflict: :nothing</code> as options to <code>Repo.insert/2</code> and it will ensure you don’t have duplicate jobs.</p>
<h4><a name="p-130994-h-2-insert-helper-2" class="anchor" href="#p-130994-h-2-insert-helper-2" aria-label="Heading link" rel="nofollow"></a>2. Insert Helper</h4>
<p>Create a helper inside your Repo that will check for existing jobs before trying to insert:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def insert_unique(changeset, opts \\ []) do
  worker = get_change(changeset, :worker)

  case get_by(Oban.Job, worker: worker, state: "scheduled") do
    nil -&gt;
      insert(changeset, opts)

    _job -&gt;
      {:ignored, changeset}
  end
end
</code></pre>
<p>That function is a bit rough, but you get the idea.</p>
<p>Neither of these are as convenient as declaring it in the worker, i.e. <code>use Oban.Worker, unique_for: :timer.minutes(1)</code>. I’ll think about this some more!</p>
<aside class="quote no-group" data-username="jaimeiniesta" data-post="41" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jaimeiniesta/48/1063_2.png" class="avatar"> jaimeiniesta:</div>
<blockquote>
<p>Tagging jobs so they can be found quickly.</p>
</blockquote>
</aside>
<p>Honestly, I hadn’t considered first class tags before. This can be accomplished by providing additional fields to <code>args</code>.</p>
<p>Here we are adding an additional <code>tag</code> value to the args:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">%{id: record.id, tag: "dependent"}
|&gt; Oban.Job.new()
|&gt; MyApp.Repo.insert()
</code></pre>
<p>Later, if the <code>record</code> is deleted we can also delete any dependent jobs within the same transaction:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">dependents =
  Oban.Job
  |&gt; where([j]. j.state in ["available", "scheduled"])
  |&gt; where([j], fragment("?-&gt;&gt;'tag' = 'dependent' and ?-&gt;&gt;'id' = ?::text", j.args, ^record.id)

Ecto.Multi.new()
|&gt; Ecto.Multi.delete(:delete, record)
|&gt; Ecto.Multi.delete_all(:jobs, dependents)
|&gt; MyApp.Repo.transaction()
</code></pre>
<p>I hope those ideas are somewhat helpful. Thanks for checking out Oban <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="130994" data-batch-url="/posts/batch_likers">
                        7
                      </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/oban-reliable-and-observable-job-processing/22449/44">Post #43</a>
	                </div>
	            </div>
              <div id="likers-container-130994" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="130994"
                     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 #43"></div>
  </section>
</div>
    <div class="postbit" id="131446" data-post-id="131446">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sorentwo" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sorentwo/120/37360_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sorentwo
                    <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 class="user-title">
									<span>Oban Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Oban v0.4.0 has been released. As with the previous release, there are a bunch of fixes and added features that came from this thread and issues on GitHub. Thanks again <img src="https://forum.elixirforum.com/images/emoji/apple/purple_heart.png?v=15" title=":purple_heart:" class="emoji" alt=":purple_heart:" loading="lazy" width="20" height="20"></p>
<p>Note that there are some breaking changes included in this release, but they are all minor changes that only take a find-and-replace to fix:</p>
<p>Directly from the <a href="https://github.com/sorentwo/oban/blob/master/CHANGELOG.md#v040--2019-06-10" rel="noopener nofollow ugc">CHANGELOG</a>:</p>
<h3><a name="p-131446-added-1" class="anchor" href="#p-131446-added-1" aria-label="Heading link" rel="nofollow"></a>Added</h3>
<ul>
<li>
<p>[Oban] Add <code>Oban.drain_queue/1</code> to help with integration testing. Draining a queue synchronously executes all available jobs in the queue from within the calling process. This avoids any sandbox based database connection issues and prevents race conditions from asynchronous processing. Thanks to <a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a></p>
</li>
<li>
<p>[Oban.Worker] Add <code>backoff/1</code> callback and switch to exponential backoff with a base value as the default. This allows custom backoff timing for individual workers.</p>
</li>
<li>
<p>[Oban.Telemetry] Added a new module to wrap a default handler for structured JSON logging. The log handler is attached by calling <code>Oban.Telemetry.attach_default_logger/0</code> somewhere in your application code. (Inspired by a similar feature in Redix)</p>
</li>
<li>
<p>[Oban.Queue.Producer] Guard against Postgrex errors in all producer queries using a circuit breaker. Failing queries will no longer crash the producer. Instead, the failure will be logged as an error and it will trip the producer’s circuit breaker. All subsequent queries will be skipped until the breaker is enabled again approximately a minute later.</p>
<p>This feature simplifies the deployment process by allowing the application to boot and stay up while Oban migrations are made. After migrations have finished each queue producer will resume making queries. Thanks to <a class="mention" href="/u/philss" rel="nofollow">@philss</a>. Side note, the solution was inspired by a discussion between <a class="mention" href="/u/keathley" rel="nofollow">@keathley</a> and <a class="mention" href="/u/adkron" rel="nofollow">@adkron</a> on the most recent Elixir Outlaws.</p>
</li>
</ul>
<h3><a name="p-131446-changed-2" class="anchor" href="#p-131446-changed-2" aria-label="Heading link" rel="nofollow"></a>Changed</h3>
<ul>
<li>
<p>[Oban] Telemetry events now report timing as <code>%{duration: duration}</code> instead of <code>%{timing: timing}</code>. This aligns with the <code>telemetry</code> standard of using  <code>duration</code> for the time to execute something.</p>
</li>
<li>
<p>[Oban] Telemetry events are now broken into <code>success</code> and <code>failure</code> at the event level, rather than being labeled in the metadata. The full event names are now <code>[:oban, :success]</code> and <code>[:oban, :failure]</code>.</p>
</li>
<li>
<p>[Oban.Job] Rename <code>scheduled_in</code> to <code>schedule_in</code> for readability and consistency. Both the <code>Oban</code> docs and README showed <code>schedule_in</code>, which reads more clearly than <code>scheduled_in</code>. Thanks <a class="mention" href="/u/lukerollans" rel="nofollow">@lukerollans</a></p>
</li>
<li>
<p>[Oban.Pruner] Pruning no longer happens immediately on startup and may be configured through the <code>:prune_interval</code> option. The default prune interval is still one minute. Again, thanks <a class="mention" href="/u/philss" rel="nofollow">@philss</a></p>
</li>
</ul>
<h3><a name="p-131446-fixed-3" class="anchor" href="#p-131446-fixed-3" aria-label="Heading link" rel="nofollow"></a>Fixed</h3>
<ul>
<li>[Oban.Migrations] Make partial migrations more resilient by guarding against missing versions and using idempotent statements.</li>
</ul>
<p><a href="https://hexdocs.pm/oban/0.4.0/Oban.html" rel="noopener nofollow ugc">v0.4.0 Docs</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131446" data-batch-url="/posts/batch_likers">
                        10
                      </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/oban-reliable-and-observable-job-processing/22449/45">Post #44</a>
	                </div>
	            </div>
              <div id="likers-container-131446" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131446"
                     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 #44"></div>
  </section>
</div>
    <div class="postbit" id="131451" data-post-id="131451">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="sorentwo" data-post="45" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sorentwo/48/37360_2.png" class="avatar"> sorentwo:</div>
<blockquote>
<p>Side note, the solution was inspired by a discussion between <a class="mention" href="/u/keathley" rel="nofollow">@keathley</a> and <a class="mention" href="/u/adkron" rel="nofollow">@adkron</a> on the most recent Elixir Outlaws.</p>
</blockquote>
</aside>
<p>Thanks for putting this out there. It is nice to know that our talks have an impact outside those of us that sit on the show. I’m delighted that this talk is one that people are seizing. This idea came from this episode <a href="https://elixiroutlaws.com/42" class="inline-onebox" rel="noopener nofollow ugc">Elixir Outlaws Episode 42: Carriage Return Line Feed</a>?</p>
<p>Do you have a link to the commits that actually implemented the change? I’d love to take a look.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131451" data-batch-url="/posts/batch_likers">
                        6
                      </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/oban-reliable-and-observable-job-processing/22449/46">Post #45</a>
	                </div>
	            </div>
              <div id="likers-container-131451" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131451"
                     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 #45"></div>
  </section>
</div>
    <div class="postbit" id="131452" data-post-id="131452">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I think I found the commit. <a href="https://github.com/sorentwo/oban/commit/876c4eaa621e6ca42acc05bc1489c82a7d61fcb3" class="inline-onebox" rel="noopener nofollow ugc">Guard against Postgrex errors in queue producers · oban-bg/oban@876c4ea · GitHub</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131452" 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/oban-reliable-and-observable-job-processing/22449/47">Post #46</a>
	                </div>
	            </div>
              <div id="likers-container-131452" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131452"
                     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 #46"></div>
  </section>
</div>
    <div class="postbit" id="131456" data-post-id="131456">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sorentwo" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sorentwo/120/37360_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sorentwo
                    <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 class="user-title">
									<span>Oban Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="adkron" data-post="46" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/adkron/48/3110_2.png" class="avatar"> adkron:</div>
<blockquote>
<p>I’m delighted that this talk is one that people are seizing.</p>
</blockquote>
</aside>
<p>Absolutely, thanks for putting the show out there.</p>
<p>I had been weighing how to properly handle the original issue (application crashing while deploying migrations because the table wasn’t available). The discussion around what is expected failure and what can be considered a “responsive” system came at the perfect time.</p>
<aside class="quote no-group" data-username="adkron" data-post="47" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/adkron/48/3110_2.png" class="avatar"> adkron:</div>
<blockquote>
<p>I think I found the commit.</p>
</blockquote>
</aside>
<p>That’s the one <img src="https://forum.elixirforum.com/images/emoji/apple/+1.png?v=15" title=":+1:" class="emoji" alt=":+1:" loading="lazy" width="20" height="20">. The change itself was rather minor and focused on a specific set of expected failures—if the <code>oban_jobs</code> table doesn’t exist or has structural inconsistencies it shouldn’t crash the rest of the application.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131456" 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/oban-reliable-and-observable-job-processing/22449/48">Post #47</a>
	                </div>
	            </div>
              <div id="likers-container-131456" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131456"
                     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 #47"></div>
  </section>
</div>
    <div class="postbit" id="131461" data-post-id="131461">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>That is an excellent and simple solution. I especially like that you logged the information to make sure that your system is observable. You also had a test which, of course, makes me smile.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131461" 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/oban-reliable-and-observable-job-processing/22449/49">Post #48</a>
	                </div>
	            </div>
              <div id="likers-container-131461" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131461"
                     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 #48"></div>
  </section>
</div>
    <div class="postbit" id="131743" data-post-id="131743">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m wondering about using oban to organize jobs that use ffmpeg.</p>
<p>It looks like the dampener feature you mentioned would work well with ffmpeg since it goes off mem/cpu instead of delegating to the beam - did I understand that correctly? If so, awesome =)</p>
<p>My main question is around &gt; 1 apps accessing jobs… I’d like the main app to queue a job, but I want a separate app to run the job.</p>
<p>So in the main app:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Oban.Job.new(queue: :default, worker: :"SeparateApp.Worker") 
</code></pre>
<p>Where SeparateApp.Worker doesn’t actually exist in the main app.. Then I actually define the SeparateApp.Worker in the separate app.</p>
<p>Is that a bad way of doing it? I was just thinking ffmpeg has different resource needs scales differently.</p>
<p>Alternatively, I could both queue the job and run the job in the separate app via api, and I believe still get job visibility (when your UI comes out) in the main app (providing it uses the same db). So it would be a separate elixir/phoenix app running in docker exposing its own api.</p>
<p>I had also considered just using aws here. So aws s3 adds a job to aws batch which calls a bash script in a docker container with ffmpeg. I’m guessing this would be more efficient computing wise, but it would lose the visibility and portability Oban provides.</p>
<p>Curious on any thoughts!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131743" 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/oban-reliable-and-observable-job-processing/22449/50">Post #49</a>
	                </div>
	            </div>
              <div id="likers-container-131743" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131743"
                     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 #49"></div>
  </section>
</div>
    <div class="postbit" id="131752" data-post-id="131752">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sorentwo" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sorentwo/120/37360_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sorentwo
                    <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 class="user-title">
									<span>Oban Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="gdub01" data-post="50" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/gdub01/48/3939_2.png" class="avatar"> gdub01:</div>
<blockquote>
<p>It looks like the dampener feature you mentioned would work well with ffmpeg since it goes off mem/cpu instead of delegating to the beam - did I understand that correctly?</p>
</blockquote>
</aside>
<p>That feature isn’t quite baked yet, it definitely won’t be ready for a while. The version I had been envisioning would track reductions/memory usage from executing processes to automatically scale queues up and down based on workload. Tying that to OS processes would be significantly more difficult, especially for something like FFMpeg which is multi-threaded itself and could use all available cores even from a single job.</p>
<aside class="quote no-group" data-username="gdub01" data-post="50" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/gdub01/48/3939_2.png" class="avatar"> gdub01:</div>
<blockquote>
<p>My main question is around &gt; 1 apps accessing jobs… I’d like the main app to queue a job, but I want a separate app to run the job.</p>
</blockquote>
</aside>
<p>You can achieve this with Oban quite easily. Remember, only the exact queues passed to the Oban supervisor will be started and there isn’t any global configuration. You can use <code>SeparateApp.Worker.new</code> to enqueue the job from your main app and so long as the main app isn’t running that worker’s queue it will be ignored.</p>
<p>Here’s a more concrete example. First, define the worker with a queue other than <code>:default</code>:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule SeparateApp.Worker do
  use Oban.Worker, queue: :video_processing

  @impl true
  def perform(args) do
    # process with ffmpeg
  end
end
</code></pre>
<p>Then, configure your apps to start only the queues they should be processing:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir"># In the supervisor of your primary app
{Oban, repo: Repo, queues: [default: 20]}

# In the supervisor of your secondary app
{Oban, repo: Repo, queues: [video_processing: 5]}
</code></pre>
<p>Within your primary application code you can conveniently call <code>SeparateApp.Worker.new(%{})</code>. You are welcome to use the <code>Oban.Job.new/2</code> variant you listed above, but you don’t <em>need</em> to.</p>
<aside class="quote no-group" data-username="gdub01" data-post="50" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/gdub01/48/3939_2.png" class="avatar"> gdub01:</div>
<blockquote>
<p>Is that a bad way of doing it? I was just thinking ffmpeg has different resource needs scales differently.</p>
</blockquote>
</aside>
<p>IMO that is a great way of doing it. We do all of our media processing in a separate container for this exact reason. Resource usage is unpredictable and the BEAM can get so starved for CPU that it can’t cope the way it usually does.</p>
<aside class="quote no-group" data-username="gdub01" data-post="50" data-topic="22449">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/gdub01/48/3939_2.png" class="avatar"> gdub01:</div>
<blockquote>
<p>I had also considered just using aws here. So aws s3 adds a job to aws batch which calls a bash script in a docker container with ffmpeg. I’m guessing this would be more efficient computing wise, but it would lose the visibility and portability Oban provides.</p>
</blockquote>
</aside>
<p>Right, you would lose all of the execution guarantees and retry behavior. You can definitely make this work within a single umbrella/poncho, so long as you start apps in different containers.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="131752" 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/oban-reliable-and-observable-job-processing/22449/51">Post #50</a>
	                </div>
	            </div>
              <div id="likers-container-131752" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="131752"
                     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 #50"></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/22449/load_more?page=6">Load more posts (261 remaining)</a>
</div></template></turbo-stream>