Fernando Guillén

un Desarrollador Web Freelance

cabecera decorativa

nada por aquí y nada por allá ó el desarrollo de software como expresión artística.

Archive for the ‘how to’ Category

Monday, August 4th, 2008

Ruby on Rails: expirar la caché desde un script ó como activar los Sweepers como Observers

No sé si es que soy yo el liante o es que me da por hacer las cosas raras.

El caso es que me he encontrado con otro dolor de cabeza haciendo algo, en principio, relativamente sencillo.

Se trata de insertar en la BD un modelo desde un script, que más adelante será un rake. Todo iba bien, no es complicado:

m = MiModelo.new( :nombre => 'el nombre' )
m.save

Pero, algo olía mal, pues los listados de este modelo tienen una vista, y esta vista está cacheada, y si insertaba el modelo desde el script la vista no cambiaba, osea: no estaba expirando la caché.

El problema estaba en que todos los engranajes de expiración de cachés estaban en los sweepers y éstos sólo se activan si el código pasa por el application.rb, padre de todos los controladores, concretamente con el método: cache_sweeper, y no encontraba manera de activar los sweeper sin pasar por un controlador.

Estuve dando unas buenas vueltas y preguntando a colegas, resulta que la caché en Rails está altamente integrada con el controlador. Y esto tiene su sentido pues no hay caché sin renderizado y no hay renderizado sin llamada a un controlador. Pero cuando hablamos de expirar cachés no veo tan claro que deba seguir estando integrado con el controlador, pues, como vemos en mi ejemplo del script, pueden existir muchos escenarios donde sea necesaria una expiración de caché sin necesidad de pasar por un controlador.

Googleando por ahí encontré un post que según creo entender también se queja un poco del exceso de integración entre la caché y los controladores.

La primero aproximación que parece ocurrírsenos es la de usar un observer en vez de un sweeper pero el sweeper tiene implícitamente un montón de métodos muy útiles para realizar la tarea de expiración de caché, como son los expire_* y los renderizadores de urls al estilo mi_modelo_url.

Además si empezaba a migrar todos los sweepers a observers empezaba a salirme del camino de como le gusta a Rails que se hagan las cosas.

Pero es que resulta que al parecer a Rails no le gusta que se expiren cachés desde un script y el workarround para conseguirlo no es del todo limpio pero se ha conseguido activar los sweepers desde un script para que se disparen al insertar un nuevo modelo en la BD.

El workarround es obra de Daniel Rodriguez Troitiño y aquí podéis revivir la lucha hasta conseguirlo.

Está funcionando para 2.0.1 y no sé si funciona en otras versiones.

require 'action_controller/test_process'
 
ActiveRecord::Base.observers = [MiSweeper]
ActiveRecord::Base.instantiate_observers
 
MiSweeper.instance.controller = ActionController::Base.new
 
tr = ActionController::TestRequest.new
MiSweeper.instance.controller.request = tr
MiSweeper.instance.controller.instance_eval( '@url = ActionController::UrlRewriter.new(tr, {})' )
 
m = MiModelo.new( :nombre => 'el nombre' )
m.save

Vemos que se activa el sweeper como un observer y luego se inicializa con todo lo necesario para que funcione.

Muchas gracias a Daniel que se lo ha tomado como reto personal ;).

Monday, April 21st, 2008

El atajo shell del día.

Monitoreando un fichero y enviando alertas por email

Este script envía un email cada vez que aparece la palabra ‘now’ en el fichero stuff.

$ tail -f stuff | awk ' /now/ { system("mail -s \"Now Occured\"  mail@foo.com < msg") }'

Hay quién se anima el día leyendo la frase zen diaria en su calendario, o el consejo cristiano, o el chiste del pajares, son buenos recursos para comentar con los compañeros en la hora del café.

Y los hay quienes se activan con el comando o atajo shell del día.

[shell-fu]$, Recopilatorio de comandos y atajos shell.

Ya estás alimentando tu lector de feeds :)

Vía GenBeta.

Friday, April 18th, 2008

Tomcat 5.5 nuevas features: no funciona nada.

¿Dónde demonios se ha metido todo? ¿El webapps? ¿El /manager? ¿El log? ¿Que demonios pasa con los VirtualHosts?

Todas estas preguntas que arrastro desde hace tiempo, desde que Tomcat 5.0 ya no está soportado en Ubuntu.

La 5.5 viene con un montón de features, la principal es que no funciona nada de lo que me funcionaba antes.

Alguna luz se me ha abierto.

Para que funcione el /manager hay que instalar:

$ sudo aptitude install tomcat5.5 tomcat5.5-admin tomcat5.5-webapps

Y lo encontrarás en:

http://localhost:8180/manager/html/

La seguridad como siempre nos juega una mala pasada y hay que mandarla a freir lechugas:

$ sudo vim /etc/default/tomcat5.5
TOMCAT5_SECURITY=no

El webapps se encuentra aquí:

/usr/share/tomcat5.5/webapps/

Este tutorial está bastante bien.

Actualizado 2008-05-14:

En Ubuntu 8.04 vuelve a fallar todo y aunque reinstale todo el tomcat no arranca

Solución: seguir este tutorial.

Si en el  /usr/share/tomcat5.5/logs/catalina.out te aparece algo así como esto:

java.lang.ClassNotFoundException: org.apache.catalina.startup.Bootstrap

Debes reinstalar libtomcat5.5-java:

 $ sudo aptitude reinstall libtomcat5.5-java

Suerte.. mucha suerte :)

Tuesday, April 8th, 2008

Poner una aplicación Rails en producción.

Esto no es un tutorial, es una nota mental.

Entorno
  • Ubuntu 7.10
  • MySql 5.0
Instalar capistrano

Tanto en cliente como en servidor.

$ gem install capistrano
Configurar aplicación rails para Capistrano

En cliente.

$ cd #{RAILS_ROOT}
$ capify .

Editar fichero /config/deploy.rb:

require 'mongrel_cluster/recipes'

set :user, "username"
set :runner, "username"

set :application, "miaplicacion"
set :repository,  "http://www.mirepositorio.com/svn/trunk/"
set :scm_username, "username"
set :scm_password, "userpass"

set :deploy_to, "/var/www/railsapps/#{application}"  # path en el servidor
set :mongrel_conf, "#{current_path}/config/mongrel_cluster.yml"  # no tocar

role :app, "miservidor.com"       # si quieres indicar puerto miservidor.com:puerto
role :web, "miservidor.com"       # si quieres indicar puerto miservidor.com:puerto
role :db,  "miservidor.com", :primary => true # si quieres indicar puerto miservidor.com:puerto

Tuve problemas con el username y el userpass y al final les puse el mismo username y pass al usuario del sistema como al usuario del svn.

Editar /config/mongrel_cluster.yml:

---
cwd: /var/www/railsapps/miaplicacion"  # path en el servidor
log_file: log/mongrel.log
port: "5000"
environment: production
address: 127.0.0.1
pid_file: tmp/pids/mongrel.pid
servers: 2      # puertos 5000 y 5001
Preparar servidor

En servidor.

Preparamos el directorio:

$ sudo mkdir -p /var/www/railsapps
$ sudo chown username /var/www/railsapps

Fichero configuración de VirtualHost /etc/apache/sites-available/miaplicacion.miservidor.com:

#we need this as on Ubuntu by default Proxy is not allowed
<Proxy *>
  Order allow,deny
  Allow from all
</Proxy>

#Proxy balancer section (create one for each ruby app cluster)
<Proxy balancer://miaplicacion.miservidor.com_cluster>
  BalancerMember http://127.0.0.1:5000
  BalancerMember http://127.0.0.1:5001
</Proxy>

#Virtual host section (create one for each ruby app you need to publish)
<VirtualHost *:80>
  ServerName miaplicacion.miservidor.com
  DocumentRoot /var/www/railsapps/miaplicacion/current/public/

  <Directory /var/www/railsapps/miaplicacion/current/public/ >
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
  </Directory>

  ErrorLog /var/log/apache2/error_miaplicacion.miservidor.com_log
  CustomLog /var/log/apache2/access_miaplicacion.miservidor.com_log combined

  #Rewrite stuff
  RewriteEngine On

  # Check for maintenance file and redirect all requests
  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
  RewriteRule ^.*$ /system/maintenance.html [L]

  # Rewrite index to check for static
  RewriteRule ^/$ /index.html [QSA]

  # Rewrite to check for Rails cached page
  RewriteRule ^([^.]+)$ $1.html [QSA]

  # Redirect all non-static requests to cluster
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ balancer://miaplicacion.miservidor.com_cluster%{REQUEST_URI} [P,QSA,L]
</VirtualHost>

Activamos el VirtualHost:

$ sudo a2ensite miaplicacion.miservidor.com

Recargamos Apache:

$ sudo /etc/init.d/apache reload
Subir primera versión a servidor

En cliente.

$ cap deploy:setup
Preparar BD en servidor

En servidor.

Esto seguro que se puede hacer desde Capistrano:

$ mysql> create database midatabase;
$ mysql> grant all privileges on midatabase.* to username@localhost identified by 'userpass';
$ rake db:migrate
Próximos despliegues

En cliente.

$ cap deploy

Y si hay migraciones entonces hay que ejecutarlas en el servidor (aunque seguro que se puede hacer con el Capistrano).

Tuesday, April 8th, 2008

Procedimiento almacenado con cursor en MySQL

Aquí dejo el código de un procedimiento almacenado de MySQL que usa un cursor.

Esto no es un tutorial es una nota mental.

DROP procedure IF EXISTS test_cursor
/
 
CREATE procedure test_cursor()
 
begin
 
--
-- variables
--
declare hasMoreRows bool DEFAULT true;
declare _field1 varchar(20);
declare _field2 varchar(20);
 
--
-- the cursor
--
declare cur cursor FOR
 
  SELECT
      cl.LIBRARY_NAME,
      cl.LIBRARY_DESCRIPTION
  FROM
      CAT_LIBRARIES AS cl
  ;
 
declare continue handler FOR SQLSTATE '02000'
    SET hasMoreRows = false;
 
--
-- create table test
--
DROP TABLE IF EXISTS test_cursor;
 
CREATE TABLE `test_cursor` (
  `field1`  varchar(20) NULL,
  `field2`  varchar(20) NULL
);
 
--
-- open the cursor
--
open cur;
 
fetch cur INTO
  _field1,
  _field2;
 
while hasMoreRows do
 
--
-- ####### WALK:INI ########
--
 
  INSERT INTO
      test_cursor
  SET
    field1 = _field1,
    field2 = _field2
  ;
 
--
-- ####### WALK:END ########
--
 
  fetch cur INTO
    _field1,
    _field2;
 
end while;
 
close cur;
 
end;
/

Aquí está el fichero con el código fuente.

Friday, March 14th, 2008

Crear otro repositorio subversion.

Esto no es un How-To, es una nota mental.

Creando el repositorio

$ sudo svnadmin create  /home/svn/mirepositorio
$ sudo chown www-data.svn -R /home/svn/mirepositorio

Configuración del apache para el nuevo repositorio:

$ sudo vim /etc/apache2/mods-available/dav_svn.conf
<Location /svn/mirepositorio>
  DAV svn
  SVNPath /home/svn/mirepositorio
  AuthType Basic
  AuthName "mirepositorio's Subversion Repository"
  AuthUserFile /etc/apache2/htpasswd
  Require valid-user
</Location>

Añadimos un usuario:

$ sudo htpasswd -b /etc/apache2/htpasswd usuario clave

Recargamos apache:

$ sudo /etc/init.d/apache2 reload

Comprobamos:

navegador: http://fernandoguillen.info/svn/mirepositorio/
consola:  $ svn checkout http://fernandoguillen.info/svn/mirepositorio

Crear las carpetas iniciales:

$ svn mkdir http://fernandoguillen.info/svn/mirepositorio/trunk
$ svn mkdir http://fernandoguillen.info/svn/mirepositorio/branches
$ svn mkdir http://fernandoguillen.info/svn/mirepositorio/tags

Primer import:

$ svn import http://fernandoguillen.info/svn/mirepositorio/trunk

Mi sistema:

Ubuntu Gutsy Gibon 7.10
Subversion version 1.4.4
Apache 2
Thursday, March 13th, 2008

Munin la bestia parda del monitoreo de servicios

Asistí a una de las aulas The Cocktail sobre Munin.

Me quedé impresionado, ahora mismo acabo de terminar de instalar y me ha costado 15 minuntos.

Es la gran bestia parda:

1) Apenas requiere configuración.

2) Permite sistema de nodos y master.

3) Monitorea cosas que nisiquiera entiendo como es capaz de monitorear.

4) Te autodetecta todo lo que tiene el servidor y se pone a monitorearlo todo sin que le tengas que explicar nada.

Increible, una joya.

Monday, October 1st, 2007

Google Analytics y PhpBB

Podemos usar las estadísticas de google analytics en nuestro foro basado en PhpBB fácilmente.

Editamos los ficheros:

  • simple_footer.tpl
  • overall_footer.tpl

De vuestra plantilla, por ejemplo:

  • /templates/subSilver/simple_footer.tpl
  • /templates/subSilver/overall_footer.tpl

Y ponemos el script del google analytics justo antes de la etiqueta de cierre del body: </body>

Monday, October 1st, 2007

Tuneando Eclipse en Ubuntu

Si eres de los que les das mucho tute al eclipse y notas como cada 2 por 3 se te cuelga o se queda pillado pensando en dios sabe que.. imprescindible arrancar eclipse con estos argumentos:

-vmargs -Xms512m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=128m

Para poner estos argumentos en el punto de menú puedes arrastrar el punto de menú del eclipse a tu barra de tareas o escritorio y en el elemento creado pulsar con el botón derecho > Propiedades y en Comando poner:

/usr/bin/eclipse -vmargs -Xms512m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=128m

Lo que estamos haciendo es asignar más memoria a la máquina virtual java donde se ejecuta eclipse, este truco no es apto para máquinas con menos de 1GB de Ram.

Suerte.

Friday, August 17th, 2007

Compartir el escaner en red

Cada vez me quedo más maravillado con esto del Ubuntu (6.10).

Ahora estoy con una impresora multifunción HP F380 instalándola en el servidor de la oficina para que pueda ser accesible desde cualquier terminal instalada en la intranet.

No voy a entrar en pormenores con la instalación de la modalidad impresora por que ha sido un “Instalar nueva impresora > siguiente > siguiente > siguiente”, tampoco voy a explicar como se instala el escaner en modo local por que ni siquiera se instala, simplemente abres el Gimp y “Archivo > Adquirir > Xsane > Device Dialog” y él solito te encuentra el escaner instalado en local y te abre la interface de escaneado.

Lo que sí tiene un pelín de ‘consola’ es configurar el escaner en modo servidor y atender peticiones de los clientes de la red.

Instalar servidor

Instalamos los paquetes necesarios

  • sane
  • sane-utils
  • xinetd

Ya sea mediante el gestor de paquetes gráfico o en consola:
$ sudo aptitude install xinetd sane sane-utils

Retocamos los ficheros de configuración

Añadimos la red de nuestra intranet en el /etc/sane.d/saned.conf:
$ sudo echo "192.168.1.0/24" >> /etc/sane.d/saned.conf

Configuramos el servicio saned para que lo arranque xinetd, para ello creamos un fichero llamado /etc/xintetd.d/saned y escribimos esto:
service sane
{
disable = no
socket_type = stream
wait = no
user = saned
group = saned
server = /usr/sbin/saned
protocol = tcp
}

Comprobamos que el puerto que usará nuestro servicio saned está bien configurado:
$ grep "sane" /etc/services
sane-port 6566/tcp sane saned # SANE network scanner daemon

Reiniciamos xinetd por si acaso:
$ sudo /etc/init.d/xinetd restart

Instalación de los clientes

Instalamos los paquetes necesarios

  • sane
  • sane-utils

Ya sea mediante el gestor de paquetes gráfico o en consola:
$ sudo aptitude install sane sane-utils

Le decimos a saned del cliente dónde está nuestro servidor

$ sudo echo "ip_servidor_escaner" >> /etc/sane.d/net.conf

Ya está

Vamos al Menú > Aplicaciones > Gráficos > Xsane

Resolución de problemas

Comprueba que el puerto 6566 está a la escucha

En el servidor:
$ telnet localhost 6566

En el cliente:
$ telnet ip_servidor_con_escaner 6566

Mira el log de xinetd en SYSLOG

En el servidor:
$ tail -f /var/log/syslog

Sin soltar esta consola abre otra y reinicia xinetd para ver que dice:
$ sudo /etc/init.d/xinetd restart

Comprueba que el servidor detecta el escaner


$ scanimage -L
device `hpaio:/usb/Deskjet_F300_series?serial=CN74PGY0Q304KH' is a hp HP Deskjet F300 series multi-function peripheral

Comprueba que el cliente detecta el escaner


$ scanimage -L
device `net:willie.constela:hpaio:/usb/Deskjet_F300_series?serial=CN74PGY0Q304KH' is a hp HP Deskjet F300 series multi-function peripheral

Comprueba el log del saned

Para xinetd:
$ sudo /etc/init.d/xinetd stop

Inicia saned en consola con debug:
$ saned -d20

Desde cliente haz peticiones:
$ scanimage -L

Sitios de referencia

Castellano

English

un Desarrollador Web Freelance is proudly powered by WordPress
Entries (RSS) and Comments (RSS).