Autotest con advertencias en Growl

Written on May 7th, 2008
.

He buscado en la red un método para “enganchar” la utilidad de testeo Autotest en Ruby y el sistema de mensajes de sistema Growl en Mac OS X y la verdad es que no me fue muy bien.
Una vez modificado el archivo .autotest en mi $home ya funciona a la perfección. Relato a continuación como obtener esta maravilla.
Basta instalar Growl en Mac OS tal que así:

wget http://growl.info/files/Growl-1.1.2.dmg
open Growl-1.1.2.dmg
cd /Volumes/Growl\ 1.1.2/Extras/growlnotify
less install.sh
sudo ./install.sh
cd
hdiutil detach /Volumes/Growl\ 1.1.2

y luego descargarte un par de imágenes para hacer los mensajes un poco más bonitos

cd ~
wget http://blog.internautdesign.com/files/rails_fail.png
wget http://blog.internautdesign.com/files/rails_ok.png
mkdir -p Pictures/Rails_Growl/
mv rails_fail.png Pictures/Rails_Growl/rails_fail.png
mv rails_ok.png Pictures/Rails_Growl/rails_ok.png

luego se edita el fichero .autotest que he modificado un poquillo

require 'autotest/redgreen'
require 'autotest/html_report'
require 'autotest/menu'
module Autotest::Growl

  def self.growl msg, options={}
    salida = "growlnotify -n autotest --image \"#{options[:img]}\"
                   -p #{options[:pri]} -d #{rand(100)} -m \"#{msg}\" \"Tests\" #{options[:sticky]}"
    system salida
  end

  Autotest.add_hook :ran_command do |at|
    results = [at.results].flatten.join("\n")
    output = results.slice(/(\d+)\s+assertions?,\s*(\d+)\s+failures?,\s*(\d+)\s+errors?/)
    failures = $~[3].to_i + $~[2].to_i
    options = (failures > 0)? {:img=>"/Users/#{ENV["USER"]}/Pictures/Rails/fail.png",
                                            :pri => 0, :sticky => "" } :
                                           { :img => "/Users/#{ENV["USER"]}/Pictures/Rails/ok.png",
                                             :pri => 0,:sticky => "" }
    output = output.gsub(/assertions/, "aserciones").gsub(/failures/, "fallos").gsub(/errors/, "errores")
    if output
      growl "#{output}", options
    end
  end
end

y listo ya podemos correr test en apps ruby y que se nos notifique en growl

Autotest con Growl

Búsqueda en Rails con Sphinx

Written on February 11th, 2008
.

Cuando lo que quieres es maximizar el rendimiento de tu aplicación en consultas y búsquedas en una base de datos con millones registros normalmente utilizar el indexador y buscador de MySql no es la mejor opción.

Desde hace poco se mueve por la red Sphinx, pero la verdad es que está pegando muy fuerte, digamos que es el nginx del mundo de la búsqueda (rápido y ruso) según Evan Weaver.
Sphinx se divide de 2 componentes:

  • Indexador: es la parte que procesa toda la información recogida por un crawler y genera uno o varios índices.
  • Buscador: componente que consulta el índice y recupera la información resultante

Instalación

Para instalarlo en GNU/Linux o en cualquier sabor de *nix necesitamos compilar desde las fuentes par eso hacemos:

$ wget http://www.sphinxsearch.com/downloads/sphinx-0.9.7.tar.gz
$ tar xvzf sphinx-0.9.7.tar.gz
$ cd sphinx-0.9.7
$ ./configure --with-mysql-includes=/opt/local/include/mysql5/mysql/
--with-mysql-libs=/opt/local/lib/mysql5/mysql/
$ make
$ sudo make install

Lógicamente los parámetros –with-mysql-includes y –with-mysql-libs tendrás que poner los tuyos propios. En el primer caso serán los ficheros cabecera que nos conectan con mysql y en el segundo será la ruta a las librerías de mysql.
En este tutorial estoy configurando para MySql pero también se puede hacer para PostgreSQL.

Ligándolo con Rails

Inicialmente voy a utilizar el plugin UltraSphinx de Evan que está genial para emprezar con un sphinx.conf auto-generado. Despues indexamos el contenido entero de lo que nos interese.

El ruido que está haciendo en la red es porque es tremendamente rápido, por ejemplo para una base de datos con una tabla con 1.5 millones de registros el chaval lo hace en solo unos pocos minutos. La rapidez de búsqueda es tambien muuy rápida. Desforturnadamente he tenido problemas con mi aplicación Rails con el plugin UltraSphinx instalado – algunos errores muy extraños sucedieron.

Habiendo probado varios plugins para Sphinx me decanté por probar acts_as_sphinx. Despues de algunas modificaciones en el fichero sphinx.conf (y volver a reindexar) la búsqueda estaba trabajando y mucho más importante, también sobre mi aplicación Rails. Una opción alternativa es Sphincter pero tiene una documentación limitada.

Indexando y flipando

Ahora sobre nuestra aplicación Rails corremos:

$ rake sphinx:index
$ rake sphinx:start

Indexando en mi MacBook…

$ time rake sphinx:index
using config file 'sphinx.conf'...
indexing index 'items'...
collected 1455733 docs, 1255.2 MB
sorted 182.4 Mhits, 100.0% done
total 1455733 docs, 1255246639 bytes
total 438.695 sec, 2861316.50 bytes/sec, 3318.32 docs/sec
real    7m25.307s
user    4m28.963s
sys     0m17.578s

Y ahora sobre rails

Vasmos a probar con el plugin acts_as_sphinx via consola (ruby script/console) el término ‘Rails’, ordenando por fecha de publicación.

>> search = Item.find_with_sphinx 'Rails',
           :sphinx => {
                       :sort_mode => [:attr_desc, 'pub_date'], :page => 1
            },
            :order => 'items.pub_date DESC'; 0
=> 0
>> search.total
=> 1000
>> search.total_found
=> 73717
>> search.time
=> "0.000"

Esto es, un índice de 943Mb de almenos 1.5 millones de elementos. Nótese que los resultados de la búsqueda se limitaron a 1000 en el fichero de configuración sphinx.conf.

En el controlador de Rails, la búsqueda se hace a través de:
@items = Item.find_with_sphinx(params[:query],
:sphinx => {:sort_mode => [:attr_desc, 'pub_date'], :limit => 50, :page => (params[:page] || 1)},
:order => 'items.pub_date DESC')

Actualizando el índice de Sphinx

Como para cada casi toda taréa en Rails, existe una tarea de _rake_ para actualizar el índice de Sphinx que puede ser llamado mediante una entrada en cron, frente a las actualizaciones en ‘vivo’.
El comando rotate nos permite reindexar el índice mientras el demonio de Sphinx está corriendo, forzando el reinicio una vez se haya completado

$ rake sphinx:rotate

Configuración de Lighttpd sobre Linux con PHP5, Ruby on Rails y SSL

Written on November 12th, 2007
.

LighttpdRecientemente he migrado mi server casero de Apache a Lighttpd, con la eterna promesa de la reducción consumo de recursos, sobre todo para deploys de múltiples aplicaciones en Rails. No se si es una panacea, pero aquí voy a relatar los puntos más algidos sobre la configuración de un server de estas características, así como mis valoraciones iniciales e intermedias.

Primer comentar que mi principal objetivo era conseguir una configuración lo más simplificada y menos estresante de cara a minimizar el tiempo de configuracion. Lighttpd es inmediato en GNU/Linux, y con pocos pasos tenemos un server para desarrollo muy bueno. Vamos allá

Instalación

Partimos de una Debian estable en la que ya había corriendo, como digo, un apache 2.0 del que últimamente no estaba muy contento ya que, mi server está muy limitado en recursos de memoria. Recientemente he encontrado un módulo de 64 Mb más, por lo que el server se quedaría con 200 mb de memoria física, que para un server casero no está nada mal.

Pues como siempre se instala un server y despues de limpiar la configuración anterior de apache en command line:

sudo aptitude install lighttpd openssl mysql php5-cgi

Instalo php5-cgi para utilizar el módulo fastcgi del lighty. Listo ya esta nuestro server instalado.

Configuración

Aquí configuraremos el soporte de PHP y Ruby para despues configurar nuestros virtual hosting, de forma muy simple, y el soporte para SSL.

El php5 ya lo tenemos instalado de antes, por lo que no voy a explicar como se hace, pero la decisión de instalar PHP5 es simple, ahora no hay soporte para PHP4 y además la versión PHP5 tiene muchisimas mejoras respecto a su antecesor. Si alguno de vosotros prefiere PHP4 la instalación es muy parecida a esta y resulta trivial.
Editamos el archivo /etc/lighttpd/lighttpd.conf y añadimos el soporte para fastcgi

server.modules              = (
            "mod_access",
            "mod_alias",
            "mod_accesslog",
            "mod_fastcgi",
[....]

Ahora configuraremos el módulo fastcgi en el archivo /etc/lighttpd/conf-available/10-fastcgi.conf

fastcgi.server    = ( ".php" =>
 ((
 	"bin-path" => "/usr/bin/php5-cgi", # ruta al wrapper php5-cgi, php4-cgi
 	"socket" => "/tmp/php.socket",     # ruta al socket de php
 	"max-procs" => 2,				   # numero máximo de procesos
 	"idle-timeout" => 20,
 	"bin-environment" => (
 		"PHP_FCGI_CHILDREN" => "4",
 		"PHP_FCGI_MAX_REQUESTS" => "10000"
 	),
 	"bin-copy-environment" => (
 		"PATH", "SHELL", "USER"
 	),
 	"broken-scriptfilename" => "enable"
 ))
# y ahora la configuración para aplicaciones rails
".fcgi" =>
        ( "dominio.com" =>
        (
               "socket" => "/tmp/rails-new.socket",
               "bin-path" => "/var/www/rails_app/public/dispatch.fcgi", #ruta al dispatcher rails
               "bin-environment" => ( "RAILS_ENV" => "production" )
               )
        )
)

Reiniciamos el server

# /etc/init.d/lighttpd restart

Y ya tenemos un lighty con php5

Ahora podemos configurar distintos hosting de forma muy muy simple, y además muy intuitiva, así como de distintos subdominios. Editamos el archivo /etc/lighttpd/lighttpd.conf y añadimos según convenga:

$HTTP["host"] == "subdominio.dominio.com" {
	server.document-root = "/var/www/subdominio.dominio.com/" }
$HTTP["host"] == "sub.dominio.com" {
	server.document-root = "/var/www/dominio.com/subdominio" }
$HTTP["host"] == "dominio2.es" {
	server.document-root = "/var/www/dominio2.es/" }

Como veis la configuración es inmediata.

SSL

Activaremos aquí el soporte para cifrado de la conexión para que ciertas zonas de nuestro server tengan más seguridad, aquí teneis un manual más extenso de generación de certificados para lighttpd

$SERVER["socket"] == "dominio.com:443" {
	ssl.engine = "enable"
	ssl.pemfile = "/etc/lighttpd/dominio.com/dominio.com.pem" #certificado del servidor
	ssl.ca-file = "/etc/lighttpd/dominio.com/CA_issuing.crt" #certificado intermedio
	server.name = "dominio.com"
	server.document-root = "/home/lighttpd/dominio.com/https" # path del servidor
	server.errorlog = "/var/log/lighttpd/dominio.com/serror.log"
	accesslog.filename = "/var/log/lighttpd/dominio.com/saccess.log"
}

Reiniciamos el server

# /etc/init.d/lighttpd restart

Y si nada ha fallado tenemos nuestro lighttpd totalmente funcional.

Recursos y Valoración

Mi valoración inicial es que el lighttpd, de primeras es mucho más fácil de administrar (bajo mi punto de vista), lógicamente bajo el recorte de funcionalidades respecto a apache, la configuración si se lee resulta muy intuitiva y con solo leerla aprendes la forma de configuración.
En cuanto al consumo de recursos, en mi server sin iniciar ningún servidor de aplicaciones, en este caso mongrel, el consumo de memoria se redujo un 30%, es decir

Mas información

Podeis encontrar más información en la página www.lighttpd.net