2015-07-16 5 views
4

Я запускаю Rails 4.2.0 с Ruby 2.0.0. Я перебираю модель Production.all и звоню production.finish! в цикле .each. My finish! метод, в конце, удаляет себя с помощью self.destroy. Но каждая неопределенная запись будет выполняться дважды в одном цикле.Двойное выполнение кода

def finish! 
    self.progress = true 
    self.save # that other crontabs can't access me anymore if the crontabs overlap 

    if DeliveredProduction.find_by_production_id(self.id) 
    # send me a notification, why this object still exists? 
    else 
    DeliveredProduction.create!(:production_id => self.id) # Each undefined times a get an Exception here because the production_id is already insert! 
    # ... 
    # do things here 
    end 
    self.destroy # my debug logs says that each entry was successful deleted 
end 

Есть ли ошибка в Rails 4.2.0 или Ruby 2.2.0p0? Только через 1-2 дня выполняется однократное выполнение. Этот код будет выполнен crontab. Я также обновляю все Production на итерации с progress = true, так что позже crontabs не смогут получить доступ к этим объектам. В моем журнале отладки говорится, что второе выполнение одной и той же Продукции происходит в одно и то же время (то же самое) через несколько секунд.

+3

Поскольку вы не используете явную транзакцию, вы все равно можете получить состояние гонки перед 'self.save'. Из вашего примера неясно, откуда вызывается «finish!», За исключением того, что это как-то результат задания cron. –

+2

Возможно, есть две идентичные записи в вашем crontab или демона cron работает дважды? – Stefan

+0

Хорошая подсказка @ nic-nicolov Я буду реорганизовывать свой код, чтобы использовать транзакции и будет смотреть его. –

ответ

0

Вы должны использовать after_commit обратного вызова для таких вещей:

after_commit :deliver!, on: :update, if: ->{|me| me.progress} 

def finish! 
    self.update(progress: true) 
end 

def deliver! 
    DeliveredProduction.create!(:production_id => self.id) 
    self.destroy 
end 

Model#save не гарантирует, что запись будет сохранена, если следующая строка кода выполняется. after_commit. Просто знать предостережения after_commit:

Rails documentation on 'after_commit'

Смежные вопросы