Uso de Couchbase Ruby Gem con EventMachine

Como habrá podido comprobar, el nuevo gema ruby couchbase ha sido lanzado recientemente. La versión 1.2.2 es principalmente una versión de mantenimiento con varias correcciones de errores, pero todavía se puede probar una nueva característica experimental: la integración con Máquina de eventos biblioteca. Este post te dará una rápida introducción sobre cómo empezar a usar Couchbase Server con tus aplicaciones basadas en el modelo asíncrono EventMachine.

La integración de EventMachine sólo es accesible (actualmente) en sistemas tipo UNIX (como Linux, Solaris, BSD). Debido a que utiliza fibras, también requiere MRI ruby versión 1.9 o posterior.

Configure su Sandbox

El primer paso es instalar la librería libcouchbase que maneja todos los detalles de bajo nivel del protocolo Couchbase. Puedes seguir el guía de instalación en la página oficial. Aquí sólo replicaré los pasos necesarios para una caja GNU/Linux típica (estoy usando Debian inestable):

  1. Instale la clave PGP del repositorio:

    $ wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -

  2. Configurar la fuente del repositorio. Aquí estoy usando el enlace para Ubuntu 12.04, pero en general no importa porque vamos a usar el plugin EventMachine, que viene incorporado en la propia gema. Los paquetes están en diferentes repositorios de paquetes construidos usando el mismo código base; la única diferencia es la versión de las librerías IO (libevent, libev) incluido en la versión de la distribución.

    $ sudo wget -O/etc/apt/sources.list.d/couchbase.list http://packages.couchbase.com/ubuntu/couchbase-ubuntu1204.list

  3. Instala las cabeceras de libcouchbase, la biblioteca central y los símbolos de depuración. Una vez más, es posible que desee instalar herramientas de línea de comandos o uno de los IO backends, pero eso no es necesario para la tarea que nos ocupa.

    $ sudo apt-get update
    $ sudo sudo apt-get install libcouchbase-dev libcouchbase2-core libcouchbase-dbg
     

    Ya está. 

    Ahora tienes que instalar Servidor CouchbaseSiga las instrucciones del sitio oficial. Después de la instalación obtendrá la consola de administrador que se ejecuta en http://localhost:8091 y también la API REST accesible en el mismo puerto. Siga los pasos de configuración iniciales y, finalmente, asignará un bucket con el nombre "default".

  4. Por último, hay que instalar la gema. Es tan fácil como escribir esto en el terminal:

    $ gem install couchbase
    Construyendo extensiones nativas. Esto podría llevar un tiempo...
    Instalado con éxito couchbase-1.2.2
    1 gema instalada
    Instalando la documentación de ri para couchbase-1.2.2...
    Instalando la documentación RDoc para couchbase-1.2.2...

Creación de la aplicación

Para demostrar la integración, vamos a construir una sencilla aplicación de chat utilizando EventMachine y el registro de añadir para todos los eventos allí a un cubo Couchbase. Es extremadamente fácil construir una aplicación asíncrona con EventMachine y para demostrarlo voy a poner el código fuente completo en este post (también se encuentra en ejemplos/chat-em de las fuentes de la gema).

clase ChatServer < EM::Connection

  @@clientes = []

  def post_init
    @nombredeusuario = nil
    send_data("*** ¿Cuál es tu nombre?n")
  fin

  def recibir_datos(datos)
    si @nombredeusuario
      broadcast(datos.strip, @nombredeusuario)
    si no
      nombre = data.gsub(/s+|[[]]/, '').strip[0..20]
      if nombre.vacío?
        send_data("*** ¿Cuál es tu nombre?n")
      si no
        @nombredeusuario = nombre
        @@clients.push(self)
        broadcast("#{@nombredeusuario} se ha unido")
        send_data("*** Hola, #{@nombre_usuario}!n")
      fin
    fin
  fin

  def desvincular
    @@clients.delete(self)
    broadcast("#{@nombredeusuario} se ha marchado") if @nombredeusuario
  fin

  def broadcast(mensaje, autor = nil)
    prefijo = autor ? "" : "***"
    @@clientes.each do |cliente|
      unless cliente == self
        client.send_data("#{prefijo} #{mensaje}n")
      fin
    fin
  fin

fin

EventMachine.run do
  # pulsa Control + C para parar
  Signal.trap("INT") { EventMachine.stop }
  Signal.trap("TERM") { EventMachine.stop }

  EventMachine.start_server("0.0.0.0", 9999, ChatServer)
fin

Este es el típico servidor EventMachine basado en EM::Connection. Para aquellos que no conocen el significado de estos métodos redefinidos aquí es un extracto de la documentación oficial:

EventMachine::Connection es una clase que es instanciada por el bucle de procesamiento de EventMachine cada vez que se crea una nueva conexión. (Las nuevas conexiones pueden ser iniciadas localmente a un servidor remoto o aceptadas localmente desde un cliente remoto). Cuando un objeto Connection es instanciado, mezcla la funcionalidad contenida en el módulo definido por el usuario especificado en las llamadas a connect o start_server. Los módulos manejadores definidos por el usuario pueden redefinir cualquiera o todos los métodos estándar definidos aquí, así como añadir código adicional arbitrario que también se mezclará.

EventMachine gestiona un objeto heredado de EventMachine::Connection (y que contiene el código de usuario mezclado) por cada conexión de red que esté activa en un momento dado. El bucle de eventos llamará automáticamente a los métodos de los objetos EventMachine::Connection cada vez que se produzcan eventos específicos en las conexiones correspondientes, como se describe a continuación.

Esta clase nunca es instanciada por el código de usuario, y no publica un método de inicialización. Los métodos de instancia de EventMachine::Connection que pueden ser llamados por el bucle de eventos son: #post_init, #connection_completed, #receive_data, #unbind, #ssl_verify_peer (si se utiliza TLS), #ssl_handshake_completed

Todos los demás métodos de instancia definidos aquí son llamados únicamente por código de usuario.

El protocolo es muy simple y orientado a la línea. Para cada conexión EventMachine creará una instancia de ChatServer, que primero preguntará el nombre del nuevo participante y luego emitirá todos sus mensajes al grupo. Puedes usar tu herramienta favorita que te permita comunicarte a través de un protocolo de texto arbitrario, como telnet por ejemplo o nc. Aquí hay un ejemplo de sesión entre puntos finales.

~ $ telnet localhost 9999 ??? ~ $ nc localhost 9999
Intentando 127.0.0.1... *** ¿Cuál es tu nombre?
Conectado a localhost. Alice
El carácter de escape es "^]". *** ¡Hola, Alice!
*** ¿Cuál es tu nombre? ??? *** bob se ha unido
hola a todos
*** ¡Hola, Bob! ¡Hola, Bob! ¿Cómo estás?
hola a todos ^C
¡Hola, Bob! ¿Cómo estás? ??? ~ $
*** Alice se ha ido ***
^]                                  ???
telnet> Conexión cerrada. ???
~ $                                 ???

Ahora es el momento de añadir un poco de Couchbase. Imagina que me gustaría mantener todos los mensajes en una base de datos distribuida tan eficientemente como pueda. Couchbase es la respuesta :). Para ello necesito:

Implementar un método de registro en la clase ChatServer, que debe aceptar el mensaje y un autor opcional (para los eventos del sistema será nil):

def log(mensaje, autor = nil)
  Couchbase.bucket.incr("log:key", :initial => 1) do |res|
    entrada = {
      'time' => Time.now.utc,
      'autor' => autor || "[sistema]",
      'message' => mensaje
    }
    Couchbase.bucket.set("log:#{res.value}", entrada)
  fin
fin

Luego añado una llamada a log(message, author) en el método broadcast justo antes de iterar todos los clientes conectados. Y envuelvo EventMachine.start_server con Couchbase::Bucket#on_connect callback, para ejecutar el servidor justo después de que el cliente se haya conectado. La ejecución del bucle resultante tendrá este aspecto:

EventMachine.run do
  # pulsa Control + C para parar
  Signal.trap("INT") { EventMachine.stop }
  Signal.trap("TERM") { EventMachine.stop }

  Couchbase.connection_options = {:async => true, :engine => :eventmachine}
  Couchbase.bucket.on_connect do |res|
    if res.success?
      EventMachine.start_server("0.0.0.0", 9999, ChatServer)
    si no
      puts "No se puede conectar a Couchbase Server: #{res.error}"
    fin
  fin
fin

Eso es todo por ahora. En el futuro podemos ampliar este ejemplo para utilizar técnicas más modernas como em-synchrony y quizás websockets. Esté atento a las actualizaciones de este blog.

Puntos extra

Sólo el registro puede no ser tan interesante, con Couchbase Server puedes realizar análisis simples con consultas View usando la maravilla incremental Map-Reduce de Couchbase. Por ejemplo, aquí está la función Map para obtener todas las entradas en orden cronológico.

function (doc, meta) {
  if (doc.message) {
    if (doc.author == "[system]" && doc.time) {
      emit(new Date(doc.time), "*** " + doc.message);
    } else {
      emit(new Date(doc.time), " " + doc.message);
    }
  }
}

Y la salida JSON.

{"filas_totales":6, "filas":[
  {"id": "log:1″, "key": "2013-02-11T19:08:05.000Z", "value": "*** alice se ha unido"},
  {"id": "log:2″, "key": "2013-02-11T19:08:18.000Z", "value": "*** bob se ha unido"},
  {“id”:”log:3″,”key”:”2013-02-11T19:08:38.000Z”,”value”:” hi everyone”},
  {"id": "log:4″, "key": "2013-02-11T19:08:48.000Z", "value":" ¡hola, bob! ¿cómo estás?"},
  {"id": "log:5″, "key": "2013-02-11T19:08:58.000Z", "value": "*** alice se ha ido"},
  {"id": "log:6″, "key": "2013-02-11T19:09:01.000Z", "value": "*** bob se ha ido"}
]}

Bueno, eso es todo por ahora. Disfrute de esta nueva característica experimental. Será totalmente compatible en una futura versión. Si tiene algún problema, por favor, envíe un mensaje a la sección Seguimiento de problemas del proyecto RCBC. Las correcciones y contribuciones también son siempre bienvenidas y es de código abierto bajo licencia Apache 2.0. Encontrará el fuentes en github.

Comparte este artículo
Recibe actualizaciones del blog de Couchbase en tu bandeja de entrada
Este campo es obligatorio.

Autor

Publicado por Sergey Avseyev, Ingeniero SDK, Couchbase

Sergey Avseyev es Ingeniero SDK en Couchbase. Sergey Avseyev es responsable del desarrollo del conector Kafka, y la biblioteca subyacente, que implementa DCP, el protocolo de replicación de Couchbase. También mantiene PHP SDK para Couchbase.

Deja un comentario

¿Listo para empezar con Couchbase Capella?

Empezar a construir

Consulte nuestro portal para desarrolladores para explorar NoSQL, buscar recursos y empezar con tutoriales.

Utilizar Capella gratis

Ponte manos a la obra con Couchbase en unos pocos clics. Capella DBaaS es la forma más fácil y rápida de empezar.

Póngase en contacto

¿Quieres saber más sobre las ofertas de Couchbase? Permítanos ayudarle.