2016-04-12 6 views
3

Я использую Rails 4 с импрессионистом и resque gem.Rails 4 - Импрессионист Внутри объекта Resque Background

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

Обычно я бы войти впечатление с помощью impressionist(@article, unique: [:session_hash]), но переместить его в BG через Resque я сейчас делаю что-то вроде этого ...

articles_controller:

def show 
    . 
    . 
    . 
    Resque.enqueue(ImpressionLogger, @article.id) 
end 

приложение/работники/impression_logger .rb:

class ImpressionLogger 

    @queue = :impression_queue 

    def self.perform(article_id) 
    article = Article.find(article_id) 
    impressionist(article, unique: [:session_hash]) 
    end 

end 

когда я поставил его, как это, когда спасательное пытается обработать задание, она возвращается undefined method "impressionist" for ImpressionLogger:Class. Как вы думаете, что лучший способ сделать это? Я не уверен, как включить методы импрессиониста внутри моего рабочего.

ответ

1

Вопрос

Ваша проблема связана с тем, что она выглядит как импрессионистов на уровне контроллера за счет включения модуля с помощью метода impressionist в инициализаторе двигателя на любых случаях ActionController:

https://github.com/charlotte-ruby/impressionist/blob/master/lib/impressionist/engine.rb#L11

Вы пытаетесь вызвать импрессионист метод из обычного класса, вызываемого в Resque-задании, поэтому он не будет определять этот метод.

Решение

Это своего рода грубых, но если вы действительно хотите использовать импрессионист, мы можем углубиться в это ... Глядя на фактической реализации импрессиониста метода найден here, мы видим следующее:

def impressionist(obj,message=nil,opts={}) 
    if should_count_impression?(opts) 
    if obj.respond_to?("impressionable?") 
     if unique_instance?(obj, opts[:unique]) 
     obj.impressions.create(associative_create_statement({:message => message})) 
     end 
    else 
     # we could create an impression anyway. for classes, too. why not? 
     raise "#{obj.class.to_s} is not impressionable!" 
    end 
    end 
end 

Предполагая, что вы бы называть что-то вроде этого вручную (как вы хотите от Resque работы) ключ эти три линии:

if unique_instance?(obj, opts[:unique]) 
    obj.impressions.create(associative_create_statement({:message => message})) 
end 

Обертка, если кажется, важна, если вы хотите реализовать функциональность this. Кажется, что это так. Вызов associative_create_statement, по-видимому, вытягивает параметры, основанные на имени контроллера, а также параметры, переданные из Rack, такие как строка useragent и IP-адрес (here). Таким образом, вам придется решить эти значения до вызова Resque-задания.

Что я хотел бы предложить на этом этапе - это реализовать класс Resque, который принимает два параметра: article_id и параметры показа, которые вы хотите. Класс resque затем просто сразу создаст впечатление на впечатляющий объект. Ваш Resque класс стал бы:

class ImpressionLogger 
    @queue = :impression_queue 

    def self.perform(article_id, impression_params = {}) 
    article = Article.find(article_id) 
    article.impressions.create(impression_params) 
    end 
end 

И ваш метод контроллера будет выглядеть примерно так:

def show 
    . 
    . 
    . 
    Resque.enqueue(ImpressionLogger, @article.id, associative_create_statement({message: nil})) if unique_instance?(@article, [:session_hash]) 
end 

Отказ

Там есть довольно большой отказ от ответственности, которая приходит с делать это таким образом, хотя ... метод associative_create_statement отмечен как защищенный, а unique_instance? отмечен как частный ... поэтому ни один из них не является частью общедоступного API-интерфейса импрессионистского gem, поэтому этот код может сломаться tween версии драгоценного камня.

+0

Кроме того, чтобы прояснить, это не то, что можно просто решить, включив/расширив ImpressionistController в классе Resque, поскольку он полагается на доступ к базовым параметрам Rack, а также такие вещи, как имя контроллера для входящего запрос. Чтобы заставить его работать то же самое, вам придется разрешить параметры в контроллере, а затем передать их в Resque. – photoionized

+0

Большое вам спасибо за это. Это действительно работает и будет выполняться как быстрое исправление. просто нужно потратить время и развернуть свое собственное решение. @photoionized – Kathan

1

Импрессионист правильно установлен с помощью соединителя? Если это необходимо, Rails следует загрузить в вашу среду. Я бы проверил, можете ли вы получить доступ к функциональности impressionist в другом месте вашего кода Rails (т. Е. Без прохождения Resque) в качестве первого шага для его отладки.

+0

Спасибо за быстрый ответ. Да, импрессионист установлен правильно. Я использую его без resque в течение нескольких месяцев, и он отлично записывает показы. Причина resque - столбец показов в БД становится очень большим, а запрос sql для проверки уникальности занимает несколько секунд. @Matt – Kathan

+0

У вашей задачи рейка есть флаг ': environment' в Rakefile, например' task: task_name =>: environment do ... '? Это то, что передает среду Rails для задачи. – Matt

0

Как вы начинаете своих работников-спасателей? Если вам нужна загруженная среда Rails, попробуйте rake environment resque:work.

https://github.com/resque/resque/wiki/FAQ#how-do-i-ensure-my-rails-classesenvironment-is-loaded

+0

Я загружаю среду в файл .rake и запускаю работника в терминале через 'rake resque: work QUEUE = *' ... похоже, что resque работает нормально, но когда работник пытается обработать задание, он ставит он находится в области «неудачных рабочих мест». @Brian – Kathan

+0

Можете ли вы попробовать изменить команду терминала на «rake environment resque: work QUEUE = *»? Это должно загрузить среду Rails, в том числе импрессионист. – Brian

+0

Извините за поздний ответ. Это не сработало ... по-прежнему error @Brian – Kathan