Starling ignora mis observers y mailers

Hola gente, a ver si a alguien se le ocurre qué puede estar sucediendo
aquí…

Estamos implementando un sistema de mensajería interna para una
comunidad de usuarios. Básicamente el sistema lo que hace es que un
administrador para enviar un mensaje a todos los usuarios, crea un
objeto SentMessage…

sent_message = SentMessage.create(:subject => ‘hola amigos’, :body =>
‘solo queremos saludaros’)

y después se ejecuta un metodo que se encarga de crear un
ReceivedMessage para todos los usuarios:

sent_message.create_receiveds_for_all_users

Este método simplemente hace un bucle y crea a cada usuario un
ReceivedMessage con los textos del SentMessage:

class SentMessage < ActiveRecord::Base

(…)

def create_receiveds_for_all_users
User.find(:all).each do |recipient|
recipient.received_messages.create( :subject => self.subject,
:body =>
self.body)
end
end

end

Como el bucle de usuarios puede llevar mucho rato si hay muchos
usuarios (ahora estamos probando con 50.000 y lo hace a un ritmo de
1.900 inserts por minuto), la llamada a este metodo la hacemos a
través de starling. O sea, en lugar de

sent_message.create_receiveds_for_all_users

hacemos:

sent_message.push(‘create_receiveds_for_all_users’)

usando la sintaxis del genial plugin de @fesplugas, simplified_starling
[1]

Y hasta aquí todo funciona estupendo.

El problema viene cuando queremos que además, cuando a un usuario se
le crea un ReceivedMessage en su inbox, se le envíe además una
notificación por email. Para ello lo que hacemos es crearnos un
mailer, ReceivedMessageMailer, y un observer, ReceivedMessageObserver,
que, en after_create, se encarga de enviar el email al usuario.

Si lo hacemos sin starling todo funciona bien:

sent_message.create_receiveds_for_all_users

pero si lo hacemos a través de starling, hace todo pero ignora lo del
mailer. Es como si el observer no existiera, no hace nada ni da
ningúnmensaje de error:

sent_message.push(‘create_receiveds_for_all_users’)

Así que lo que probamos es a no usar un observer, sino directamente a
ponerlo con after_create en el modelo ReceivedMessage. Y pasa lo
mismo: directamente funciona, pero a través de starling, lo ignora
como si no ejecutara el callback.

Y para probar a ver si fuera que starling no lanza callbacks, podemos
la llamada al mailer directamente dentro del método:

def create_receiveds_for_all_users
User.find(:all).each do |recipient|
received_message = recipient.received_messages.create( :subject
=> self.subject,
:body =>
self.body)
ReceivedMessageMailer.deliver_notification(received_message)
end
end

quitando los callbacks de antes y… pasa exactamente lo mismo. Sin
starling funciona bien, pero con starling no hace nada con el mailer,
sin mensaje de error, solo que lo ignora.

Así que aquí van mis dudas:

  • starling ignora observers?
  • starling ignora callbacks?
  • starling ignora mailers?
  • necesito echarme una siesta?

Como nota aclaratoria, para el envío de mails usamos ARMailer, o sea,
que los mailers heredan de ActionMailer::ARMailer… Por si a alguien
le suena que haya incompatibilidad entre starling y ARMailer… Pero
si lo hacemos directamente con ActionMailer estandar, hace lo mismo, o
sea, nada.

Y para más info, usamos Rails 2.0.2.

Gracias por su colaboración, ciudadanos. :slight_smile:

[1] http://github.com/fesplugas/simplified_starling/tree/master

On Jul 10, 2008, at 1:24 PM, Jaime I. wrote:

  • starling ignora observers?

No

  • starling ignora callbacks?

No

  • starling ignora mailers?

No

  • necesito echarme una siesta?

¿Siesta de 20 minutos o siesta de pijama?


¿Puedes hacer un pastie de tu observer? Es super raro que no funcione.
El plugin (simplified_starling) internamente lo que hace es llamar al
método de instancia o de clase. En este caso llamarà al de instancia.

Al hacer …

 sent_message.push('create_receiveds_for_all_users')

Lo que se mete en la cola es algo como …

 { :type => "Model", :id => 1, :task =>

‘created_receiveds_for_all_users’ }

El plugin lo que hace es un get del elemento de la cola instanciarlo.

 job = STARLING.get('product_queue')
 job[:type].constantize.find(job[:id]).send(job[:task])

Puedes confirmar que pasas por el observer? Lo tienes loggeado?

def after_save(model)
model.logger.info “TuObserver#after_create(#{model.class})
called”

end

A ver si tienes suerte, y sino … siesta.

2008/7/10 Francesc E. [email protected]:

¿Puedes hacer un pastie de tu observer? Es super raro que no funcione.

Claro!

http://pastie.org/231459

Puedes confirmar que pasas por el observer? Lo tienes loggeado?

   def after_save(model)
     model.logger.info "TuObserver#after_create(#{model.class}) called"
      ...
   end

Si, y pasa lo mismo… si lo llamo sin starling, lo loguea:

ReceivedMessageObserver#after_create(ReceivedMessage) called

y si lo llamo con starling, no lo loguea. Como si no hubiera observer.

A ver si tienes suerte, y sino … siesta.

Ya me he puesto el pijama :slight_smile:

Después de la siesta probaré a pasar de simplified_starling y usar
starling directamente… y si no, beanstalkd…

Gracias!

On Jul 10, 2008, at 3:06 PM, Jaime I. wrote:

Después de la siesta probaré a pasar de simplified_starling y usar
starling directamente… y si no, beanstalkd…

Yo lo tengo funcionando con observers, callbacks y funciona sin
problema. No es problema de la cola.

y si lo llamo con starling, no lo loguea. Como si no hubiera
observer.

¿Donde miras el log?

On Jul 10, 2008, at 3:06 PM, Jaime I. wrote:

¿Puedes hacer un pastie de tu observer? Es super raro que no
funcione.

Claro!

http://pastie.org/231459

No habia mirado el pastie … me da la sensación de que no lo estas
haciendo bien.

¿Ese observer … que “observa”?

 class IndexObserver < ActiveRecord::Observer

    observe :post   <======= Creo que te falta algo como esto ...

    def after_save(model)
      model.logger.info "IndexObserver#after_save(#{model.class})

called"
end

 end

Lo que no entiendo es que te este funcionando desde el modelo …

On Jul 10, 2008, at 5:19 PM, Jaime I. wrote:

Mírate “naming conventions”, página 283 de The Rails Way. De todos
modos por probar que no quede, lo he añadido y el resultado es el
mismo.

Me he dado cuenta justo al enviar el email que es una convencion lo de
los observers.

2008/7/10 Francesc E. [email protected]:

bien.
¿Ese observer … que “observa”?
class IndexObserver < ActiveRecord::Observer

   observe :post   <======= Creo que te falta algo como esto ...

   def after_save(model)
     model.logger.info "IndexObserver#after_save(#{model.class}) called"
   end
end

Lo que no entiendo es que te este funcionando desde el modelo …

Holas Francesc, el observer está bien. No hace falta poner la línea
“observe…” ya que por convención, Rails deduce el nombre de la clase
a observar quitando la parte de “Observer” del final del nombre.
Mírate “naming conventions”, página 283 de The Rails Way. De todos
modos por probar que no quede, lo he añadido y el resultado es el
mismo.

Por hacer más pruebas, tengo un modelo User con restful_authentication
y una rake task que me crea usuarios ficticios [1]. Aquí al hacer
user.activate se envía un email al usuario, de la misma manera, con un
UserMailer y un UserObserver. Pues bien, si lo hago a través de
starling, con user.push(‘activate’)… funciona!

Conclusión: que mi otro mailer/observer para los mensajes han de estar
mal definidos, voy a repasarlo a fondo.

[1] http://pastie.org/231518

Gracias!

Pues ni siesta de veinte minutos ni siesta de pijama. Me ha hecho
falta dormir toda la noche para darme cuenta de que aquí lo único que
fallaba era mi cabeza.

Resulta que no me acordaba de que es necesario reiniciar starling para
que coja los cambios en la aplicación, y por eso cuando yo le enviaba
trabajos a la cola, seguía procesándolos con la lógica antigua.

En resumen: que starling me funciona perfectamente, con observers y
mailers, y que simplified_starling también es muy chulo.

Gracias!