Search code examples
ruby-on-railssidekiq

stack level too deep, run function before it WARNs


WARN: stack level too deep
Than i'm getting on my sidekiq console after few minutes. I have a background script for sidekiq and repeating it every 0.1 second. I am running only with 1 concurrency. But after it says "WARN: stack level too deep", the worker starts over again, and all my local variable data refresh. And it's bad.
Then i would like to run a script before "stack level too deep" warning. How to call a function before i get this warning?


I run sidekiq: bundle exec sidekiq -c 1
My sidekiq:

class HardWorker
  include Sidekiq::Worker
  require 'sidekiq/api'
  sidekiq_options :retry => false

  def perform
    self.recalculate
  end

  def recalculate
    @number = 0
    def increment
      @number = @number+1
      sleep 0.1
      puts (@number)
      increment
    end
  end
end

My console log (incrementing)

882
883
884
2014-11-30T10:39:26.973Z 5071 TID-qoeag HardWorker JID-3279857b07c31ab4481db5e8 INFO: fail: 89.005 sec
2014-11-30T10:39:26.975Z 5071 TID-qoeag WARN: {"retry"=>true, "queue"=>"default", "class"=>"HardWorker", "args"=>[], "jid"=>"3279857b07c31ab4481db5e8", "enqueued_at"=>1417339371.1692605, "error_message"=>"stack level too deep", "error_class"=>"SystemStackError", "failed_at"=>1417342603.6595845, "retry_count"=>1, "retried_at"=>1417343966.9730375}
2014-11-30T10:39:26.975Z 5071 TID-qoeag WARN: stack level too deep
2014-11-30T10:39:26.975Z 5071 TID-qoeag WARN: /home/vartotojas/.rvm/gems/ruby-2.1.2/gems/sidekiq-3.2.6/lib/sidekiq/processor.rb:110
2014-11-30T10:39:26.980Z 5071 TID-qoeag HardWorker JID-63fc10dfe81abb4fdb29a4a1 INFO: start
1
2
3

.. and i need it always to increment in background, but not in database.

If it's not possible to stop recalling the Worker, then i would like before the stack level too deep WARN, to save my last @number to Database.
How to make script before "stack level too deep" call?


Solution

  • This is the deep recursion, the disadvantage of recursion is that you can get exception (or just error). Your code have this:

    def increment
      # ...
      increment
    end
    

    So since you have so called tail recursion, you are able with some labour expand it to a .In ruby wa it will look like:

    FIXNUM_MAX = (2**(0.size * 8 -2) -1)
    def increment
      (1..FIXNUM_MAX).each do |number|
         puts number
         sleep 0.1
      end
    end