2010-07-28 13 views
14

Estoy intentando crear algo (en última instancia, una gema, pero por ahora una aplicación) que funciona de la siguiente manera.En Ruby on Rails, ¿cómo puedo persistir objetos en la memoria entre sesiones?

Supongamos, por ejemplo, que los registros DB son razas de perro. Hay una clase de padres de perros y una clase de niños para cada raza. Las razas reales no se conocen hasta el tiempo de ejecución.

Cuando el servidor comienza, cargará los registros de la base de datos y crea instancias de clases basadas en los registros, p. Puedo tener dos beagles y poodle. Cuando alguien llega al servidor, es posible que desee acceder a una de esas instancias de perro.

¿Por qué no crear la instancia sobre la marcha? En mi caso, los "perros" son básicamente clases que contienen un algoritmo y datos. El algoritmo no cambia, los datos cambian raramente (en el orden de los días), pero se accederá a la ejecución del algoritmo en sí, que utiliza datos y algunos datos dinámicos pasados, como una marca de tiempo, varias veces por segundo.

Sería tonto tener que volver a crear una instancia del objeto y cargar los datos cada vez solo para hacer una solicitud solo para volver a hacerlo en la siguiente solicitud (las solicitudes no cambian el estado del objeto) . Estaría creando y destruyendo múltiples objetos por segundo cuando podría reutilizar el mismo objeto.

no tiene sentido mantenerlo en la sesión, ya que alguien que quiere un caniche no debería necesitar tener la información de los beagles en su objeto de sesión; es irrelevante (y no escala).

¿Cómo persisto estos objetos en la memoria? Básicamente quiero una tabla de búsqueda para contener las instancias. En Java, crearía un singleton con algún tipo de hashmap o matriz que se encuentre en la memoria. En los rails intenté esto creando una clase singleton en la carpeta lib. Creo que no estoy entendiendo este derecho, que la instancia (el hecho de que es un singleton es discutible) se está perdiendo cuando la sesión desaparece.

La respuesta más cercana que encontré fue http://www.ruby-forum.com/topic/129372 que básicamente pone todo en campos y métodos de clase. De alguna manera, eso no parece correcto.

TIA!

Adición: Vengo de Java. En Java, simplemente crearía un objeto que se encuentra en el montón o quizás en un árbol JNDI y, a medida que ingresen las solicitudes HTTP, serían manejadas por un servlet o EJB o un elemento por solicitud que podría acceder al objeto persistente. Parece que no puedo encontrar el equivalente en rieles.

+0

+1 para la pregunta, tengo un árbol para fines de búsqueda. No cambiará en absoluto y no quiero construirlo en cada solicitud. – lulalala

Respuesta

8

Quizás su ejemplo sea confuso por su simplicidad. Supongo que sus objetos son bastante complicados y que su evaluación comparativa muestra que construirlos no es razonable en cada solicitud.

En el modo de producción, las clases no se descargan entre las solicitudes, pero las instancias de esas clases sí lo están. Entonces, usar los miembros de la clase de una clase suena como la forma de ir a verme. Solo úsalo para almacenar tus instancias.

class ObjectCache 
    @@objects = {:beagle => Beagle.new, :poodle => Poodle.new} 

    def lookup key 
    @@objects[key.to_sym] 
    end 
end 
+0

Gracias por la respuesta. Mencionaste "en modo de producción". Estoy intentando esto en modo de desarrollo y sigo perdiendo el objeto entre las solicitudes (incluso cuando los métodos también son métodos de clase, por ejemplo, la clave def auto.look) pero tal vez sea por el modo. Me conformaría con que funcionara por ahora, pero francamente, esta parece ser la forma incorrecta de hacerlo. – hershey

+0

No está muy bien definido lo que sucede cuando se mantienen instancias de modelos ActiveRecord entre las solicitudes, por lo que es mejor evitar esto. Si está almacenando objetos simples de Ruby, podría funcionar. – tadman

+0

Buena advertencia; Afortunadamente, estos son solo objetos de rubí, no objetos de ActiveRecord, así que no me preocupa que el estado se confunda dentro y fuera de la base de datos. El estado del objeto "perros" en el ejemplo que proporcioné arriba proviene de algunos datos cargados (leídos, nunca escritos) del DB y el algoritmo. No hay riesgo de que un objeto sea inconsistente con el DB dado que no hay ningún objeto en el DB en este caso. – hershey

6

No me preocuparía demasiado cargar y descartar objetos a menos que se te ocurra un punto de referencia que demuestre que es un problema. Cada solicitud crea una cantidad extraordinaria de objetos intermedios como una cuestión de rutina, y estos generalmente se crean y destruyen en cuestión de varios milisegundos.

En general, es mejor enfocarse en cargar solo lo que se necesita, desnormalizar su base de datos para insertar datos o métodos de acceso frecuente en una ubicación conveniente o guardar los resultados de cálculos complicados en un campo de caché.

Primero comparativa, optimice solo cuando sea necesario.

Guardar instancias de modelos en una memoria caché de clases puede funcionar, pero solo es una opción en un entorno de producción donde las clases de modelo no se vuelven a cargar con cada solicitud. También puede exponerte a errores causados ​​por datos obsoletos.

Si tiene un problema de escalabilidad que no se puede resolver con estos métodos, puede investigar la creación de un servidor persistente para una parte de su funcionalidad usando una combinación de Rack y EventMachine. Hay varias formas de construir un proceso en segundo plano que puede realizar cálculos complicados utilizando un conjunto de datos precargados, pero el enfoque específico dependerá de varias cosas, como el tipo de datos con los que está trabajando y la frecuencia con la que lo haga. se accederá.

+0

Gracias por tomarse el tiempo para responder. Escalando a un lado, esto simplemente no parece una programación adecuada. Continuamente recreando el mismo objeto es simplemente incorrecto desde el punto de vista de OO cuando el objeto mismo puede ser reutilizado. Rack parece que usa una versión mucho más ligera de Rails, no vi nada en la documentación que sugiera que puede hacer que persista Rails. EventMachine parece ser la respuesta correcta. http://www.neeraj.name/2009/12/15/ruby-eventmachine-a-short-introduction.html tiene una buena explicación de esto. Voy a echar un vistazo más profundo. – hershey

+0

La naturaleza sin estado de HTTP a menudo contribuye a problemas como este donde una solicitud puede no tener nada que ver con la siguiente, y un marco de aplicación como Rails a menudo tiene que limpiar la casa de todos los objetos utilizados en la solicitud previa para dejar espacio para la siguiente. Si necesita un entorno persistente, cree un motor que se ejecute en segundo plano y obtendrá ganancias de rendimiento masivas no solo evitando recargas redundantes, sino también operaciones asincrónicas. Escribir un servidor que "habla" el protocolo Memcache es bastante fácil y se puede usar como un caché normal incluso si computa respuestas. – tadman

+0

hablé demasiado pronto. EventMachine solo persiste dentro de la conexión. No podré mantener una conexión entre las solicitudes web, así que seguiré perdiendo el estado. ¿Alguna otra forma de construir un motor? – hershey

0

En la producción, los controladores y las clases del modelo no se vuelven a cargar entre las solicitudes, por lo que tiene varias opciones:

  • conjunto los objetos como variables de clase en su application_controller
  • crear métodos únicos en el las mismas clases de modelo que devuelven los valores
0

Sí, también se puede evitar que las clases se descarguen en el modo Desarrollo. No es solo un modo de Producción. Aunque ocurre de manera predeterminada en el modo Producción, donde debe establecerlo manualmente en el modo Desarrollo.

0

Para no volver a cargar sus clases en cada solicitud, incluso en modo de desarrollo, puede moverlas a algún lugar fuera de las rutas de carga automática (si usa valores predeterminados fuera de los directorios de la aplicación y lib). De esta forma, puede mantener estas clases de objeto entre solicitudes y, por lo tanto, usarlas para almacenar datos que son iguales para cada solicitud.