Выявление ошибок с помощью Ruby Twitter gem, методы кеширования с использованием delayed_job: Что я делаю не так?

Чем я занимаюсь

Я использую twitter gem (оболочку Ruby для API Twitter) в своем приложении, которое запустить на Heroku. Я использую планировщик Heroku для периодического выполнения задач кеширования, которые используют гем twitter для, например, обновления список ретвитов для конкретного пользователя. Я также использую delayed_job, поэтому планировщик вызывает задачу rake, которая вызывает "отложенный" метод. (см. scheduler.rake ниже). Метод проходит через «аутентификации» (для пользователей, которые прошли аутентификацию в Twitter через мое приложение) для обновления кеша ретвитов каждого авторизованного пользователя в приложении.

Мой вопрос

Что я делаю не так? Например, поскольку я использую планировщик Heroku, является ли delayed_job избыточным? Кроме того, вы можете видеть, что я не улавливаю (спасаю) никаких ошибок. Итак, если Twitter недоступен или если срок действия токена авторизации пользователя истек, все задыхается. Это, очевидно, глупо и ужасно, потому что, если есть ошибка, все это задыхается и в конечном итоге создает неудавшуюся задачу delayed_job, которая вызывает волновые эффекты для моего приложения. Я вижу, что это плохо, но я не уверен, какое решение лучше. Как / где я должен отлавливать ошибки?

Я поместил весь свой код (от планировщика до вызываемого метода) для одного из моих методов кеширования. Я просто надеюсь на маркированный список (и, возможно, какой-то код или псевдокод), отчитывающий меня за плохую практику программирования и сообщающий, где я могу что-то улучшить.

Я видел этот вопрос SO, который мне немного помогает с блоком begin / rescue, но Я мог бы воспользоваться дополнительными инструкциями по обнаружению ошибок, и одним из них более высокого уровня "это хороший способ сделать это?" самолет.

Код

Работа планировщика Heroku:

rake update_retweet_cache

scheduler.rake (в моем приложении)

task :update_retweet_cache => :environment do
  Tweet.delay.cache_retweets_for_all_auths
end

Tweet.rb, метод update_retweet_cache:

def self.cache_retweets_for_all_auths
  @authentications = Authentication.find_all_by_provider("twitter")

  @authentications.each do |authentication|
    authentication.user.twitter.retweeted_to_me(include_entities: true, count: 200).each do |tweet|
      # Actually build the cache - this is good - removing to keep this short
    end
  end
end

User.rb, метод twitter:

def twitter
  authentication = Authentication.find_by_user_id_and_provider(self.id, "twitter")
  if authentication
    @twitter ||= Twitter::Client.new(:oauth_token => authentication.oauth_token, :oauth_token_secret => authentication.oauth_secret)
  end
end

Примечание. Когда я публиковал это, я заметил, что нахожу все аутентификации "twitter" в методе "cache_retweets_for_all_auths", а затем вызываю метод "User.twitter", который конкретно ограничивает "twitter "аутентификации. Это явно избыточно, и я это исправлю.


person JoshDoody    schedule 05.04.2013    source источник


Ответы (1)


Во-первых, какова точная ошибка, которую вы получаете, и что вы хотите, чтобы произошло ее появление?

Редактировать:

Если вы просто хотите поймать ошибки и зарегистрировать их, то должно работать следующее.

def self.cache_retweets_for_all_auths
  @authentications = Authentication.find_all_by_provider("twitter")

  @authentications.each do |authentication|
    being
      authentication.user.twitter.retweeted_to_me(include_entities: true, count: 200).each do |tweet|
        # Actually build the cache - this is good - removing to keep this short
      end
     rescue => e
       #Either create an object where the error is log, or output it to what ever log you wish.
     end
  end
end

Таким образом, в случае сбоя он продолжит переход к следующему пользователю, но все равно будет записывать ошибку. В большинстве случаев с твиттером лучше сделать что-то подобное, а затем пытаться делать с каждой ошибкой отдельно. Я видел так много странностей в твиттер-API и случайных ошибок, что попытка отследить каждую ошибку почти всегда превращается в дикую погоню за гусем, хотя на всякий случай все равно хорошо отслеживать.


Далее, когда вам следует использовать what.

Вы должны использовать планировщик, когда вам нужно, чтобы что-то произошло только по времени, отложенные задания, когда это основано на действии пользователя, но «действие», которое вы собираетесь отложить, потребует слишком много времени для нормального ответа. Иногда вы можете просто поместить эту вещь прямо в контроллер.

Другими словами

Планировщик будет в порядке, если время между обновлениями X меньше, чем время, необходимое для выполнения обновления, время Y.

Если X ‹Y, тогда вы можете захотеть посмотреть на вызов логики из контроллера при доступе к каждой отдельной записи, вместо того, чтобы пытаться сделать их все сразу. Идея в том, что вы обновляете его только по прошествии определенного времени. Вы можете сохранить последнее обновление либо в самой модели в поле типа twitter_udpate_time, либо в экземпляре redis или memecache с ключом unquie для пользователя / auth.

Но если отдельное обновление по-прежнему слишком велико, тогда вам следует выполнить описанное выше, но вместо того, чтобы выполнять фактическое обновление, вызовите отложенное задание.

Вы даже можете настроить его так, чтобы он обновлял или вызывал отложенное задание только после определенного количества просмотров, чтобы еще больше ограничить количество материалов.

Возможные модные штаны

Или, если вы хотите по-настоящему фантазировать, вы все равно можете сделать это как задание cron, но иметь систему баллов, основанную на представлениях, которые взвешивают, какие записи должны быть обновлены. Идея, заключающаяся в определенных действиях, добавит баллы определенным пользователям, и если их баллы превышают определенную сумму, вы обновляете их, а затем удаляете их баллы. Таким образом, вы можете настроить таргетинг на те, которые, по вашему мнению, являются наиболее важными, или имеют наибольший трафик, или отображаются в большинстве результатов поиска и т. Д. И т. Д.


Рядом с ником придирчивый.

http://api.rubyonrails.org/classes/ActiveRecord/Batches.html

Вы должны использовать

@authentications.find_each do |authentication|

вместо того

@authentications.each do |authentication|

find_each извлекает только 1000 записей за раз, поэтому, если вы получите много аутентификаций, вы не получите сумасшедшее количество записей в памяти.

person rovermicrover    schedule 05.04.2013
comment
Привет - спасибо за отличный ответ! Во-первых, я не уверен, КАКОЙ ошибки я боюсь, потому что прошло много времени с тех пор, как она у меня появилась. Вот почему я думаю: а почему бы просто не убедиться, что я поймаю ЛЮБУЮ ошибку из Твиттера, чтобы он не мешал? Как только я начну видеть обнаруженные ошибки, я могу сделать их более детальными / точными. - person JoshDoody; 06.04.2013
comment
Затем я должен сказать, что причина, по которой я использую job / delayed_job, заключается в том, что обновление кеша занимает довольно много времени. Иногда задание выполняется в течение многих минут (даже для одного пользователя). Поэтому я периодически создаю кеш (скажем, раз в час) и удаляю старые записи раз в день. Таким образом, не будет задержек при загрузке сводной страницы (которая использует данные Twitter) И мой кеш не станет огромным. Наконец, ваш должен быть, а не блок показывает одно и то же дважды. Но мне очень интересно ваше предложение. Не могли бы вы это исправить? - person JoshDoody; 06.04.2013
comment
извините за это, должно быть .find_each вместо .each. Обновит ответ через секунду. - person rovermicrover; 06.04.2013
comment
Это отличный ответ - спасибо, что нашли время ответить на все аспекты моего вопроса и предоставили хорошие примеры и объяснения. Я очень ценю это! - person JoshDoody; 06.04.2013
comment
PS Мне нравится ваша идея назначать баллы для просмотров и обновлять кеш для тех, у кого более высокие баллы. Вот о чем я задумался: что, если они аутентифицируются в Twitter, но на самом деле никогда не смотрят данные? Это много времени для создания кеша, который никогда не будет виден. Это тоже было бы довольно легко реализовать. Спасибо еще раз! - person JoshDoody; 06.04.2013