6

¿Es seguro este subproceso de código?Rails 3 ActiveRecord .skip_callback thread safety

MyModel.skip_callback(:save, :before, :my_callback) 
my_model_instance.update_attributes(attributes) 
MyModel.set_callback(:save, :before, :my_callback) 

¿Puedo usarlo de forma segura para evitar el reinicio de la misma devolución de llamada recursivamente?

Aquí es un ejemplo

class Blog < ActiveRecord::Base 

    after_save :update_blog_theme, :if => :active_theme_id_changed? 

    # ... 

    private 

    def update_blog_theme 

    # Reuses a previously used BlogTheme or creates a new one 
    blog_theme = BlogTheme.find_by_theme_id_and_blog_id(
         self.active_theme_id, 
         self.id) 

    blog_theme ||= BlogTheme.create!( 
        :theme_id => active_theme_id, 
        :blog_id => self.id) 

    Blog.skip_callback(:save, :after, :update_blog_theme) 
    self.update_attributes!(:active_blog_theme_id => blog_theme.id) 
    Blog.set_callback(:save, :after, :update_blog_theme) 

    end 

end 
+0

Parece hacky, ¿por qué no puedes usar before_save o before_create? – apneadiving

+0

¿cuáles son los requisitos finales? – Anatoly

+0

no hay requisitos aquí, no estoy usando este código, y quizás nunca lo haga, pero encontré esta solución en Internet y me pregunté si era seguro usarla en multiprocesamiento – mcasimir

Respuesta

5

skip_callback y set_callback NO es seguro para subprocesos. Pude confirmar esto al intentar crear algunos registros dentro de sidekiq (un procesador de trabajo asincrónico con subprocesos). Tan pronto como vuelvo a habilitar las devoluciones de llamada, hay una condición de carrera que da lugar a que se llamen las devoluciones de llamada. Si comento el código de reactivación de devolución de llamada, no hay problemas.

he encontrado una serie de posibles soluciones al problema que incluye dos joyas:

  • la 'disimulado-SAVE' joya
  • joya los 'skip_activerecord_callbacks'

El disimulado-ahorrar gema parece ser la opción más directa y reveladora de la intención aquí. La gema esencialmente pasa por alto los métodos de persistencia de ActiveRecord y ejecuta SQL directamente.

También es el único que puedo decir con seguridad que es seguro para subprocesos. También es una joya muy pequeña y comprensible. La desventaja es que no llama validaciones. Por lo tanto, debería llamar validaciones usted mismo.

Anand A. Bait reunió un gran resumen de varias opciones. Soy escéptico de que las cinco opciones sean enhebrables. Las dos gemas mencionadas anteriormente se enumeran junto con otras opciones posibles en la publicación de Anand aquí: http://www.allerin.com/blog/save-an-object-skipping-callbacks-in-rails-3-application/