[Ruby/Rails] Move tweeting to DelayedJob and handle Twitter API errors
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

I have a blog where users can choose to automatically tweet our new posts by connecting their Twitter accounts. We have about 100 users doing this, so every time we publish a post it gets tweeted 100 times.

Relevant code:

# post.rb
def publish!
  self.touch :published_at
  User.auto_tweeters.each { |u| u.tweet(self.tweet_message) }
end

# user.rb
def tweet(msg) 
  client = Twitter::Client.new({ oauth_token: self.token, oauth_token_secret: self.secret })
  client.update(msg)
end

The problem is sometimes Twitter's API doesn't respond, and some users have de-authorized our Twitter app resulting in an error from the Twitter API whenever we try to send a tweet.

I'm looking for a solution to:

  1. Move the tweeting to a background worker using DelayedJob.

  2. If the Twitter API isn't available try tweeting again 1 minute later.

  3. If a user's account isn't authorized anymore handle the exception gracefully and set self.twitter_is_not_authorized on the current user to true, so it won't be returned in the User.auto_tweeters call next time.

Using Rails 3, ActiveRecord, Twitter gem, Heroku.

awarded to Wikimedia

Crowdsource coding tasks.

1 Solution


I'm going to assume that you've installed and run DelayedJob already, if not you can see the documentation here: https://github.com/collectiveidea/delayed_job

# post.rb
def publish!
  self.touch :published_at
  User.auto_tweeters.each { |u| u.delay.tweet(self.tweet_message) }
end

#in user.rb add:
handle_asynchronously :tweet
handle_asynchronously :tweet_later, :run_at => Proc.new { 1.minute.from_now }
def tweet(msg) 
    begin
      client = Twitter::Client.new({ oauth_token: self.token, oauth_token_secret: self.secret })
      if !client 
        self.twitter_is_not_authorized = 1
      else
         client.update(msg)
      end
    rescue Twitter::Error
      tweet_later(msg)
    end
end
def tweet_later
    begin
      client = Twitter::Client.new({ oauth_token: self.token, oauth_token_secret: self.secret })
      client.update(msg)
    rescue Twitter::Error
      #handle this however you want.
    end
end
From what I understand using 'handle_asynchronously' makes the usage of the delay method redundant. Correct? Anyway, whether I use the delay method or not I get the error NameError: undefined method tweet for class User. That's on the line of handle_asynchronously.
marc 9 years ago
Another question is what happens when tweet_later fails as well. I don't think creating multiple methods is well designed solution. Isn't possible to say "Okay, let's try this same method again in 15 minutes."?
marc 9 years ago