Repository: sidekiq-cron/sidekiq-cron (Ruby)

Issue:
Add support for `retry` option
We're integrating sidekiq-cron as a replacement for cron jobs in part for the automatic retry support. However we don't want jobs to retry indefinitely. For example, in our case a job that runs every 15 minutes doesn't need to retry at all, and a job that runs nightly shouldn't retry after the end of the day.

We can use `sidekiq_options retry: 5` or the like in the Job class (see [doc](https://github.com/sidekiq/sidekiq/wiki/Error-Handling#configuration)), but the retry value is dependent on the scheduling, so we'd rather include it in `schedule.yml`, like:

```yml
parse_emails_job:
  cron: 'every 15 minutes'
  class: 'ParseEmails'
  retry: false # or 5, or retry_for: 15.minutes
```

The case for supporting this configuration option seems similar to the case for supporting `queue`.

Would you be open to a PR?


Discussion:
So this would overwrite the existing and/or default retry settings set for a job just like happens currently with the queue setting?
> So this would overwrite the existing and/or default retry settings set for a job just like happens currently with the queue setting?

That's right.
Looks like an interesting feature! Please feel free to send a patch 🤝



Patch:
diff --git a/README.md b/README.md
index 40875aed..4643db68 100644
--- a/README.md
+++ b/README.md
@@ -50,6 +50,7 @@ gem "sidekiq-cron"
   'namespace' => 'YourNamespace', # groups jobs together in a namespace (Default value is 'default'),
   'source' => 'dynamic', # source of the job, `schedule`/`dynamic` (default: `dynamic`)
   'queue' => 'name of queue',
+  'retry' => '5', # Sidekiq (not supported by ActiveJob) number of retries, or false to discard on first failure
   'args' => '[Array or Hash] of arguments which will be passed to perform method',
   'date_as_argument' => true, # add the time of execution as last argument of the perform method
   'active_job' => true,  # enqueue job through Active Job interface
diff --git a/lib/sidekiq/cron/job.rb b/lib/sidekiq/cron/job.rb
index 97d82cb4..59682b6f 100644
--- a/lib/sidekiq/cron/job.rb
+++ b/lib/sidekiq/cron/job.rb
@@ -61,6 +61,7 @@ def initialize input_args = {}
           @message = args["message"]
           message_data = Sidekiq.load_json(@message) || {}
           @queue = message_data['queue'] || "default"
+          @retry = message_data['retry']
         elsif @klass
           message_data = {
             "class" => @klass.to_s,
@@ -72,7 +73,7 @@ def initialize input_args = {}
           klass_data = get_job_class_options(@klass)
           message_data = klass_data.merge(message_data)
 
-          # Override queue if set in config,
+          # Override queue and retry if set in config,
           # only if message is hash - can be string (dumped JSON).
           if args['queue']
             @queue = message_data['queue'] = args['queue']
@@ -80,6 +81,12 @@ def initialize input_args = {}
             @queue = message_data['queue'] || "default"
           end
 
+          if args['retry'] != nil
+            @retry = message_data['retry'] = args['retry']
+          else
+            @retry = message_data['retry']
+          end
+
           @message = message_data
         end
 
@@ -166,7 +173,7 @@ def enqueue_active_job(klass_const)
       end
 
       def enqueue_sidekiq_worker(klass_const)
-        klass_const.set(queue: queue_name_with_prefix).perform_async(*enqueue_args)
+        klass_const.set(queue: queue_name_with_prefix, retry: @retry).perform_async(*enqueue_args)
       end
 
       # Sidekiq worker message.
@@ -422,6 +429,7 @@ def to_hash
           active_job: @active_job ? "1" : "0",
           queue_name_prefix: @active_job_queue_name_prefix,
           queue_name_delimiter: @active_job_queue_name_delimiter,
+          retry: @retry.nil? || @retry.is_a?(Numeric) ? @retry : @retry.to_s,
           last_enqueue_time: serialized_last_enqueue_time,
           symbolize_args: symbolize_args? ? "1" : "0",
         }


Test patch:
diff --git a/test/unit/job_test.rb b/test/unit/job_test.rb
index c0768253..ae03c52f 100644
--- a/test/unit/job_test.rb
+++ b/test/unit/job_test.rb
@@ -287,6 +287,23 @@
                                  "args"=>[]}
     end
 
+    it "be initialized with 'class' and overwrite retry by settings" do
+      job = Sidekiq::Cron::Job.new('class' => CronTestClassWithQueue, retry: 5)
+
+      assert_equal job.message, {"retry"=>5,
+                                 "queue"=>:super,
+                                 "backtrace"=>true,
+                                 "class"=>"CronTestClassWithQueue",
+                                 "args"=>[]}
+
+      job = Sidekiq::Cron::Job.new('class' => CronTestClass, retry: false)
+
+      assert_equal job.message, {"retry"=>false,
+                                 "queue"=>"default",
+                                 "class"=>"CronTestClass",
+                                 "args"=>[]}
+    end
+
     it "be initialized with 'class' and date_as_argument" do
       job = Sidekiq::Cron::Job.new('class' => 'CronTestClassWithQueue', "date_as_argument" => true)
 
@@ -507,6 +524,30 @@
     end
   end
 
+  describe '#sidekiq_worker_message settings overwrite retry name' do
+    before do
+      @args = {
+        name:  'Test',
+        cron:  '* * * * *',
+        retry: 5,
+        klass: 'CronTestClassWithQueue',
+        args:  { foo: 'bar' }
+      }
+      @job = Sidekiq::Cron::Job.new(@args)
+    end
+
+    it 'should return valid payload for Sidekiq::Client with overwrite retry' do
+      payload = {
+        "retry" => 5,
+        "backtrace" => true,
+        "queue" => :super,
+        "class" => "CronTestClassWithQueue",
+        "args"  => [{:foo=>"bar"}]
+      }
+      assert_equal @job.sidekiq_worker_message, payload
+    end
+  end
+
   describe '#active_job_message' do
     before do
       SecureRandom.stubs(:uuid).returns('XYZ')