7

I have used sidekiq and redis-server to send email in background..
Problem: Its ok when used sync method to send email. i.e. in applicants_controller.rb

UserMailer.notify_applicant_assignment(current_assigned_user.id, applicant, workflow_step).deliver

However, when I use delay method to send email i.e.

in applicants_controller.rb

UserMailer.delay.notify_applicant_assignment(current_assigned_user.id, applicant, workflow_step)   

I get the following error undefined method 'background_color' for nil:NilClass in /layouts/user_mailer.html.erb:17:

Code inside mailers/user_mailer.rb

class UserMailer < ActionMailer::Base
  include Sidekiq::Worker
  default from: CommonConstants::DO_NOT_REPLY_ADDRESS
  layout 'user_mailer'
    def notify_applicant_assignment(user_id, applicant_id, workflow_step_id)
       @user = User.find(user_id)
       @organization = @user.organization
       @applicant = Applicant.find(applicant_id)
       @url = root_url + 'applicants/' + @applicant.id.to_s
       @workflow_step = WorkflowStep.find(workflow_step_id)
       mail(to: @user.email, subject: 'Applicant Assigned.')
    end
end

Code inside layouts/user_mailer.html.erb

<body style="background:#f4f4f4;">
<table width="100%" bgcolor="<%= @organization.background_color %>" cellpadding="0" cellspacing="0">
  <tr>
    <td>
      <table align="center" width="730" cellpadding="0" cellspacing="0" >

Error I got in sidekiq console

2015-03-24T08:58:14Z 5595 TID-cjors WARN: {"retry"=>true, "queue"=>"default", "class"=>"Sidekiq::Extensions::DelayedMailer", "args"=>["---\n- !ruby/class 'UserMailer'\n- :notify_applicant_assignment\n- - 4\n  - '9'\n  - '9'\n"], "jid"=>"4421abf04e7e6864c7ee9fd8", "enqueued_at"=>1427187124.323067, "error_message"=>"undefined method `background_color' for nil:NilClass", "error_class"=>"ActionView::Template::Error", "failed_at"=>1427187124.3466575, "retry_count"=>4, "retried_at"=>1427187494.9246943}
2015-03-24T08:58:14Z 5595 TID-cjors WARN: undefined method `background_color' for nil:NilClass
2015-03-24T08:58:14Z 5595 TID-cjors WARN: /home/leapfrog/projects/ATS/app/views/layouts/user_mailer.html.erb:17:in `_app_views_layouts_user_mailer_html_erb__235114594899105140_70586860'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/actionpack-4.0.4/lib/action_view/template.rb:143:in `block in render'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/activesupport-4.0.4/lib/active_support/notifications.rb:161:in `instrument'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/actionpack-4.0.4/lib/action_view/template.rb:141:in `render'
/home/leapfrog/.rvm/gems/ruby-2.1.1/gems/actionpack-4.0.4/lib/action_view/renderer/template_renderer.rb:61:in `render_with_layout'
/
Shiva
  • 11,485
  • 2
  • 67
  • 84
  • I might be missing something - but how do you provide the ```org_id``` variable? – mgrim Mar 24 '15 at 09:22
  • check in method if you are getting `@organization = @user.organization` – Sonalkumar sute Mar 24 '15 at 09:25
  • sorry, I have mistakenly posted the code I was experimenting on, now I have edited the question.. thanks for giving interest on helping me :) – Shiva Mar 24 '15 at 09:25
  • In what context is the mailer called? – mgrim Mar 24 '15 at 09:34
  • mailer is called when `applicant` is assigned to other `user` @mgrim – Shiva Mar 24 '15 at 09:37
  • Check you are getting `@organization = @user.organization and `try putting this after your notify_applicant_assignment method `handle_asynchronously :notify_applicant_assignment, :run_at => Proc.new { 5.seconds.from_now }` – Sonalkumar sute Mar 24 '15 at 09:39
  • I think your looking at the wrong error. It looks like what you posted `bgcolor="<%= @organization.background_color %>>` is on line 4 not line 17. – rkamun1 Jun 04 '15 at 19:28
  • are you setting @organization.background_color in a callback? (e.g. after_save). If so, you can't depend on these getting called if so (idempotent) – engineerDave Jun 05 '15 at 22:54

1 Answers1

3

It's very possible that the delay extension work differently then you would expect. They are different that the regular async job.

In the documentation, it is clearly stated that:

I strongly recommend avoiding delaying methods on instances. This stores object state in Redis which can get out of date, causing stale data problems.

I wouldn't be surprised if the delay extension stores the unrendered template and the mail parameters (subject, to, from, etc') rather then calling the method itself for an outdated instance.

Also, please notice that notify_applicant_assignment isn't defined as a class method (it looks like an instance method), although the Sidekiq documentation states that delay should be applied to class methods.

Any class method can be delayed via the same methods as above:

I would recommend making the notify_applicant_assignment a class method and trying again (notice the self in def self.notify_applicant_assignment vs. def notify_applicant_assignment).

class UserMailer < ActionMailer::Base
  include Sidekiq::Worker
  default from: CommonConstants::DO_NOT_REPLY_ADDRESS
  layout 'user_mailer'
    def self.notify_applicant_assignment(user_id, applicant_id, workflow_step_id)
       @user = User.find(user_id)
       @organization = @user.organization
       @applicant = Applicant.find(applicant_id)
       @url = root_url + 'applicants/' + @applicant.id.to_s
       @workflow_step = WorkflowStep.find(workflow_step_id)
       mail(to: @user.email, subject: 'Applicant Assigned.')
    end
end

Alternatively, I would recommend also using the standard async engine in applicants_controller.rb:

UserMailer.notify_applicant_assignment_async(current_assigned_user.id, applicant, workflow_step)

Please let me know how it goes, so I can research some more if there's still a need.

Good luck!

Myst
  • 18,516
  • 2
  • 45
  • 67