Mailer #delay method #84

Closed
brandonhilkert opened this Issue Mar 19, 2012 · 24 comments

Projects

None yet
@brandonhilkert
Collaborator
irb(main):004:0> UserMailer.delay.weekly_email(User.brandon.id)
TypeError: can't dump anonymous class Class
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:211:in `visit_Class'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:63:in `accept'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:246:in `block in visit_Array'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:246:in `each'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:246:in `visit_Array'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:63:in `accept'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb:36:in `<<'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/1.9.1/psych.rb:165:in `dump'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/sidekiq-0.9.1/lib/sidekiq/extensions/generic_proxy.rb:16:in `method_missing'
    from (irb):4
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands/console.rb:47:in `start'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands/console.rb:8:in `start'
    from /Users/bhilkert/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

Was hoping to use the .delay method in https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/extensions/action_mailer.rb.

Am I doing something wrong?

@rickbutton

Have you tried using the sidekiq-mailer gem?

@ryanlecompte
Contributor

Which version of Rails / Sidekiq are you using? I just tested this with the latest release and a Rails 3.0.10 application and had no issues. This error comes from trying to convert an anonymous class (i.e., one created via Class.new) to YAML. Is the result of "User.brandon.id" an integer as you'd expect?

@jc00ke
Collaborator
jc00ke commented Mar 19, 2012

@brandonhilkert are you on OS X? What version of Ruby are you using? I've saw this error when testing Sidekiq out on JRuby and it was a YAML bug when trying to convert an array.

@ryanlecompte
Contributor

Ah yes, I believe the sidekiq unit tests also fail under JRuby with similar error messages.

@jc00ke
Collaborator
jc00ke commented Mar 19, 2012

Yeah, because of this issue we won't support JRuby until 1.7.

@brandonhilkert
Collaborator

I didn't try the sidekiq-mailer gem yet. I'm on OS X, and using Ruby 1.9.3. Judging from you what you said, it may be because we're using MongoMapper, and document IDs are actually BSON Objects, so you'd have to do something like to_s on the ID before converting it?

@mperham
Owner
mperham commented Mar 19, 2012

The delayed extensions only work on Ruby 1.9.3 and JRuby 1.7. Your backtrace shows 1.9.2.

@mperham mperham closed this Mar 19, 2012
@mperham
Owner
mperham commented Mar 19, 2012

I've put a bigger warning in the wiki, thanks for the reminder: https://github.com/mperham/sidekiq/wiki/Delayed-extensions

@kulesa
kulesa commented Mar 31, 2012

I just ran into the same issue in a Rails 3.1 application on Ruby 1.9.3. I figured out it was because 'syck' was used as the default YAML engine. Adding YAML::ENGINE.yamler = 'psych' somewhere in initialization fixes the problem.

Syck.dump(Object)  # TypeError: can't dump anonymous class Class
Psych.dump(Object) # "--- !ruby/class 'Object'\n"
@mperham
Owner
mperham commented Mar 31, 2012

Great info, thank you!

@cvincent

I just tried @kulesa's solution to get this working in my Ruby 1.9.2 project, but no-go. Apparently 1.9.3 is required, even if you specify psych. I get the same can't dump anonymous class Class error even with psych on 1.9.2.

@cvincent

This quick and dirty monkey patch got it working, no change to the default yamler necessary. I put this in config/initializers/sidekiq.rb:

# Patch Sidekiq to allow usage of #delay proxy in 1.9.2.
module Sidekiq
  module Extensions
    class Proxy < (RUBY_VERSION < '1.9' ? Object : BasicObject)
      def initialize(performable, target)
        @performable = performable
        @target = target.to_s
      end
    end

    class DelayedMailer
      def perform(yml)
        (target, method_name, args) = YAML.load(yml)
        target.to_const.send(method_name, *args).deliver
      end
    end

    class DelayedModel
      def perform(yml)
        (target, method_name, args) = YAML.load(yml)
        target.to_const.send(method_name, *args)
      end
    end
  end
end

Basically I'm just passing a string of the target class rather than the class constant itself, then turning it back into a constant on the worker side. Perhaps Sidekiq could do it this way instead to support 1.9.2 users who can't immediately upgrade their production stacks to 1.9.3.

@mperham
Owner
mperham commented Apr 28, 2012

target isn't always a Class. It might be an instance, which you can't call to_const on.

@cvincent

Interesting. In that case, maybe only do target.to_s if it's a Class, otherwise just leave it as-is. Then, on the other end, only call target.constantize* if it's a String. Ruby 1.9.2 YAML doesn't mind marshaling instances, it just chokes on classes.

*to_const is an error, I should have put constantize.

@maxwell
maxwell commented Feb 8, 2013

Hey, just started seeing this bug on Heroku... did one of the recent security patches for 1.9.3 mess with this feature?

@planetmcd

I'm seeing it on heroku as well.

@planetmcd

Looks like Heroku defaults to 1.9.2. Setting the ruby version to 1.9.3 did it for me:
https://devcenter.heroku.com/articles/ruby-versions

@mperham
Owner
mperham commented Feb 18, 2013

Add ruby '1.9.3' to your Gemfile.

@planetmcd

Thanks Mike!

@jwswj
jwswj commented Jul 9, 2013

Thanks @planetmcd & @mperham

@shawndeprey

@planetmcd & @mperham
I just wanted to confirm that this definitely fixes the issue outlined here. 👍

@ajsharp
ajsharp commented Aug 12, 2013

Had the same problem on heroku. Thanks everyone!

@mperham is this exception explicitly rescued by sidekiq and then sent to stderr? It'd be easier to trace the cause of the exception with a full stack trace.

@kateray
kateray commented Sep 6, 2013

Thanks!!!!!!!

If there was a warning on https://github.com/mperham/sidekiq/wiki/Delayed-extensions it seems to be gone now. Took quite awhile for me to find this thread!

@pantsoptional

we can't afford to change to psych here, so I created a fork to change from YAML to Marshal (pericles/sidekiq@9cbda79).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment