hugopl/sidekiq.cr

Invalid type derivation

Closed this issue · 5 comments

Somehow the Crystal compiler thinks that Sidekiq::Job#retry can be of type Array(Redis::RedisValue) but I clearly mark its type here. I can't figure out what is wrong. Can anyone help?

    property retry : (Bool | Int64 | Nil)

    def to_h : Hash(String, JSON::Type)
      h = Hash(String, JSON::Type).new
      h["jid"] = jid
      h["args"] = args
      h["queue"] = queue
      h["class"] = klass
      h["created_at"] = created_at.epoch_f

      h["bid"] = bid if bid
      h["at"] = at.not_nil!.epoch_f if at
      h["failed_at"] = failed_at.not_nil!.epoch_f if failed_at
      h["retried_at"] = retried_at.not_nil!.epoch_f if retried_at
      h["enqueued_at"] = enqueued_at.not_nil!.epoch_f if enqueued_at
      h["retry_count"] = retry_count if retry_count
      h["dead"] = dead if dead
      h["backtrace"] = backtrace if backtrace
      h["retry"] = retry if retry
      h["error_class"] = error_class if error_class
      h["error_message"] = error_message if error_message
      h["error_backtrace"] = error_backtrace.not_nil!.map{|x| x.as(JSON::Type)} if error_backtrace
      h
    end
$ crystal spec
Error in ./spec/api_spec.cr:136: instantiating 'Sidekiq::SortedEntry#add_to_queue()'

      job.add_to_queue
          ^~~~~~~~~~~~

in ./src/sidekiq/api.cr:370: instantiating 'remove_job()'

      remove_job do |message|
      ^~~~~~~~~~

in ./src/sidekiq/api.cr:407: instantiating 'Sidekiq:Module#redis()'

      Sidekiq.redis do |conn|
              ^~~~~

in ./src/sidekiq.cr:15: instantiating 'Sidekiq::Pool#redis()'

    Sidekiq::Client.default_context.pool.redis do |conn|
                                         ^~~~~

in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'

      @pool.connection do |conn|
            ^~~~~~~~~~

in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'

      @pool.connection do |conn|
            ^~~~~~~~~~

in ./src/sidekiq.cr:15: instantiating 'Sidekiq::Pool#redis()'

    Sidekiq::Client.default_context.pool.redis do |conn|
                                         ^~~~~

in ./src/sidekiq/api.cr:407: instantiating 'Sidekiq:Module#redis()'

      Sidekiq.redis do |conn|
              ^~~~~

in ./src/sidekiq/api.cr:370: instantiating 'remove_job()'

      remove_job do |message|
      ^~~~~~~~~~

in ./src/sidekiq/api.cr:374: instantiating 'Sidekiq::Client#push(Sidekiq::Job)'

        Sidekiq::Client.new.push(job)
                            ^~~~

in ./src/sidekiq/client.cr:100: instantiating 'raw_push(Array(Sidekiq::Job+))'

        raw_push([job])
        ^~~~~~~~

in ./src/sidekiq/client.cr:135: instantiating 'Sidekiq::Pool#redis()'

      @ctx.pool.redis do |conn|
                ^~~~~

in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'

      @pool.connection do |conn|
            ^~~~~~~~~~

in ./src/sidekiq/pool.cr:65: instantiating 'ConnectionPool(Redis)#connection()'

      @pool.connection do |conn|
            ^~~~~~~~~~

in ./src/sidekiq/client.cr:135: instantiating 'Sidekiq::Pool#redis()'

      @ctx.pool.redis do |conn|
                ^~~~~

in ./src/sidekiq/client.cr:136: instantiating 'Redis#multi()'

        conn.multi do |multi|
             ^~~~~

in ./src/sidekiq/client.cr:136: instantiating 'Redis#multi()'

        conn.multi do |multi|
             ^~~~~

in ./src/sidekiq/client.cr:137: instantiating 'atomic_push(Redis::TransactionApi, Array(Sidekiq::Job+))'

          atomic_push(multi, payloads)
          ^~~~~~~~~~~

in ./src/sidekiq/client.cr:146: instantiating 'Array(Sidekiq::Job+)#each()'

        payloads.each do |hash|
                 ^~~~

in /usr/local/Cellar/crystal-lang/0.17.4/src/array.cr:813: instantiating 'each_index()'

    each_index do |i|
    ^~~~~~~~~~

in /usr/local/Cellar/crystal-lang/0.17.4/src/array.cr:813: instantiating 'each_index()'

    each_index do |i|
    ^~~~~~~~~~

in ./src/sidekiq/client.cr:146: instantiating 'Array(Sidekiq::Job+)#each()'

        payloads.each do |hash|
                 ^~~~

in ./src/sidekiq/client.cr:149: instantiating 'Sidekiq::Job+#to_json()'

          all << hash.to_json
                      ^~~~~~~

in ./src/sidekiq/job.cr:68: instantiating 'to_h()'

      to_h.to_json
      ^~~~

in ./src/sidekiq/job.cr:60: no overload matches 'Hash(String, JSON::Type)#[]=' with types String, (Array(Redis::RedisValue) | Bool | Int64 | Nil)
Overloads are:
 - Hash(K, V)#[]=(key : K, value : V)
Couldn't find overloads for these types:
 - Hash(String, JSON::Type)#[]=(key : String, value : Array(Redis::RedisValue))

      h["retry"] = retry if retry
       ^

@jhass @asterite Any ideas? If you have sidekiq.cr locally, just do this:

git pull
git co json_mapping
make

Sidekiq::JobProxy#retry returns this

I'm thinking of ways to improve the error message, but it's hard. Basically retry got that type from that method and it was passed to a method. Traces are already very long.

The way I found the error was:

  1. The compiler seems to believe retry has a type I didn't expect
  2. Is retry redefined in Job, or any subclass of Job redefines this method?
  3. Found Sidekiq::JobProxy#retry returning the result of an each method.

Thanks, that was it. Now I seem to have an infinite loop. Is it possible to dump a current backtrace when running crystal spec?

crystal spec -v gave me the hint I needed.