<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sampo Kuokkanen</title>
    <description>The latest articles on DEV Community by Sampo Kuokkanen (@sampokuokkanen).</description>
    <link>https://dev.to/sampokuokkanen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F678430%2F9ef1b9b7-5c0a-4db1-917c-154fc7e4cdee.jpeg</url>
      <title>DEV Community: Sampo Kuokkanen</title>
      <link>https://dev.to/sampokuokkanen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sampokuokkanen"/>
    <language>en</language>
    <item>
      <title>Ruby background processing  worker error handling comparison</title>
      <dc:creator>Sampo Kuokkanen</dc:creator>
      <pubDate>Fri, 06 Aug 2021 08:25:50 +0000</pubDate>
      <link>https://dev.to/sampokuokkanen/ruby-background-processing-worker-error-handling-comparison-4lpf</link>
      <guid>https://dev.to/sampokuokkanen/ruby-background-processing-worker-error-handling-comparison-4lpf</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oLyLOPq0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r19f27nfqxut2yxjfovg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oLyLOPq0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r19f27nfqxut2yxjfovg.jpg" alt="Photo of a coffee shop worker by Valeria Boltneva"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How do Ruby background job processing gems do their error handling? &lt;/p&gt;

&lt;p&gt;I have had to look into this, as I have my own background job gem called &lt;a href="https://rubygems.org/gems/belated"&gt;Belated&lt;/a&gt;, so I want to know a good way to do it in my own gem. &lt;/p&gt;

&lt;p&gt;A word about Belated: it runs in a different process, but uses &lt;a href="https://github.com/ruby/drb"&gt;dRuby&lt;/a&gt; to connect your main app and Belated. &lt;/p&gt;

&lt;p&gt;So, currently, in Belated I am just rescuing &lt;code&gt;StandardError&lt;/code&gt;. &lt;br&gt;
But what happens if someone passes a job with perform method like below? (failing RSpec test)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'will not crash with syntax errors'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="vi"&gt;@worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;job_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nb"&gt;proc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;SyntaxError&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;
  &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;not_to&lt;/span&gt; &lt;span class="n"&gt;raise_error&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This raises an error (SyntaxError: compile error).&lt;/p&gt;

&lt;p&gt;So let's look at how other job libraries deal with this! &lt;/p&gt;

&lt;h2&gt;
  
  
  Sidekiq
&lt;/h2&gt;

&lt;p&gt;Sidekiq is pretty much the de-facto job processing gem for Ruby. At my day job, we depend on Sidekiq to run business critical jobs having to with live streams.  &lt;/p&gt;

&lt;p&gt;Sidekiq seems to rescue Exception, but it also has a manager class to handle these exceptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;
  &lt;span class="n"&gt;process_one&lt;/span&gt; &lt;span class="k"&gt;until&lt;/span&gt; &lt;span class="vi"&gt;@done&lt;/span&gt;
  &lt;span class="vi"&gt;@mgr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processor_stopped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Sidekiq&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Shutdown&lt;/span&gt;
  &lt;span class="vi"&gt;@mgr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processor_stopped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;
  &lt;span class="vi"&gt;@mgr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processor_died&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you rescue Exception only, you end up rescuing too much, so Sidekiq is also taking care of properly handling shutdown by rescuing &lt;code&gt;Sidekiq::Shutdown&lt;/code&gt; first. &lt;/p&gt;

&lt;p&gt;A very clever approach with really nice logging too!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mperham/sidekiq/blob/e8df351f0a6b222807ecf2e05a98149187b02e48/lib/sidekiq/processor.rb#L72"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resque
&lt;/h2&gt;

&lt;p&gt;Resque, like Sidekiq, needs Redis to function. It's an older gem, still in use in many places, but Resque seems to be quite a bit slower than Sidekiq. (See &lt;a href="https://dev.to/molly/switching-from-resque-to-sidekiq-3b04"&gt;this article to learn more&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Resque also rescues &lt;code&gt;Exception&lt;/code&gt;, and then checks if that exception is shutdown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;work&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# skipping a lot of code here...&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;SystemExit&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@child&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;run_at_exit_hooks&lt;/span&gt;
  &lt;span class="n"&gt;log_with_severity&lt;/span&gt; &lt;span class="ss"&gt;:error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Failed to start worker : &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="n"&gt;unregister_worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;run_hook&lt;/span&gt; &lt;span class="ss"&gt;:worker_exit&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have to say I'm not completely sure how this is working, but the gist of it should be that in case there is something so wrong that we get a syntax error the worker will shutdown. &lt;br&gt;
Correct me if I'm wrong! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/resque/resque/blob/master/lib/resque/worker.rb#L251"&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  GoodJob
&lt;/h2&gt;

&lt;p&gt;GoodJob is an interesting new gem that uses PostgreSQL to handle connecting the processes. &lt;/p&gt;

&lt;p&gt;It seems to just rescue StandardError.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;
  &lt;span class="c1"&gt;# code that executes the job&lt;/span&gt;
  &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="no"&gt;ExecutionResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;value: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unhandled_error: &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes handling shutdown much easier. &lt;br&gt;
GoodJob, like Sidekiq, allows you to have an error handler that sends your errors to a service like Airbreak, or maybe emails them to you using an exception handling gem. &lt;br&gt;
But something like a SyntaxError will probably not get reported. (Probably quite a rare case though... and feel free to correct me if I'm wrong!)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/bensheldon/good_job/blob/main/lib/good_job/job.rb#L329"&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So... what to do with Belated? &lt;br&gt;
I think the right thing would be to just rescue Exception, but when you rescue exception, you have to also take into account shutdown. You don't want to make it impossible to actually close the program with CTRL + C. &lt;/p&gt;

&lt;p&gt;Sidekiq's approach looks really promising, but as excepted, also the most demanding one. So something like it... but simpler. For now, Belated will just crash if you feed it a proc with a syntax error in it. &lt;/p&gt;

&lt;p&gt;And here's what I ended up doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;
  &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="no"&gt;Interrupt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SignalException&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just check if I actually want to rescue the error. Normally rescuing Exception is overdoing it, and you get a Rubocop warning for it too, but in a background job process you want to keep the worker working even if there is a syntax error in the job is processing. &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>sidekiq</category>
      <category>resque</category>
    </item>
  </channel>
</rss>
