开发者

Heroku - Issue due to multiple Dynos

开发者 https://www.devze.com 2023-02-15 05:43 出处:网络
In my rails app, I\'m using the SendGrid pa开发者_如何转开发rse API which posts mail to my server. Every now and then SendGrid\'s Parse API submits the same email twice.

In my rails app, I'm using the SendGrid pa开发者_如何转开发rse API which posts mail to my server. Every now and then SendGrid's Parse API submits the same email twice.

When I get a posted mail I place it in the IncomingMail model. so in order to prevent this double submitting issue, I look at each IncomingMail when processing to see if there is a duplicate in the table within the last minute. That tested great on development, it caught all the double submissions.

Now I pushed that live to heroku, where I have 2+ dynos and it didn't work. My guess being that it has something to do with replication. So that being the case, how can scalable sites with multiple server deal with something like this?

Thanks


You should look at using a background job queue. Heroku has "Workers" (which was Delayed Job). Rather than sending the email immediately, you push it onto the queue. Then one or more Heroku 'workers' need to be added to your account, and each one will pull jobs in sequence. This means there can be a short delay (depending on load) before the email is sent, but this delay is not presented to the user, and should there be a lot of email to send you just add more workers.

Waiting for an external service like an email provider on each user action is dangerous because any network problem will take down your site as several users have to 'wait' for their HTTP requests to be responded to while Heroku is blocked with these third party calls.

In this situation with workers each job would fail but would be retried and eventually succeed.


This sounds like it could be a transaction issue. If you have multiple workers running simultaneously their operation may be 'interleaved'. For instance this sequence of events would result in 2 mails being sent.

Worker A : Checks for an existing record and doesn't find one Worker B : Checks for an existing record and doesn't find one Worker A : Post to Sendgrid Worker B : Post to Sendgrid

You could wrap everything in a transaction to keep this from happening. Something like this should do it.

class IncomingMail < ActiveRecord::Base

  def check_and_send(email_address)
    transaction do
      # your existing code for preventing duplicates and sending
    end
  end

end
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号