Para los que estén desarrollando aplicaciones con Django para Google App Engine ( GAE ), se habrán encontrado con el problema de las sesiones de Django, las cuales no son compatibles con GAE.
Si bien existen múltiples alternativas que van desde frameworks enteros dedicados a la integración de los middlewares de Django en GAE hasta simples handlers de sesión basados en el storage de Google, yo he encontrado varias razones para no usarlos, que pueden ser válidas o no, pero son mis razones:
- Los frameworks hechos para una mejor integración entre Django y GAE, o son muy inmaduros o tienen demasiada funcionalidad que no me interesan. Por otro lado, prefiero hacer las cosas yo mismo y aprender un poco más.
- Las sesiones basadas en storage suelen no escalar muy bien.
- En el billing del GAE, el storage es más caro que el memcache.
Con estas simples razones en mente, encontré una solución a mi dilema: MemSession
MemSession es un proyecto hosteado en GitHub ( https://github.com/leonelquinteros/memsession ) y se trata de un muy pequeño y simple middleware para Django que sirve de handler para sesiones y que utiliza Memcache como sistema de almacenamiento de las mismas.
El setup es muy sencillo (hay instrucciones in inglés en el archivo README del proyecto) y consta de 2 simples pasos:
1) Clonar o bajar el módulo python ( session.py ) directamente de GitHub y alojarlo dentro del PATH del proyecto.
2) Agregar el módulo a la lista de middleware del proyecto Django en cuestión.
Una vez hecho esto, el middleware se encargará de inicializar automáticamente una sesión única por cada usuario de nuestra aplicación, y pondrá a disposición el objeto memSession como una propiedad de todos los objetos request de la aplicación.
El objeto memSession tiene 3 métodos básicos que proporcionan la funcionalidad de sesión que necesitamos:
- memSession.read( key )
- memSession.write( key, value)
- memSession.delete( key )
Creo que tanto los métodos como los parámetros de los mismos son bastante auto-explicativos.
Para resumir, me parece una librería extremadamente útil para la simplicidad que tiene y creo que puede escalar bastante bien haciendo uso de Memcache, aunque no lo he probado.
Y por último, el link del proyecto en GitHub: https://github.com/leonelquinteros/memsession
Infectogroovalistic
Web development, systems design, software architecture
miércoles 12 de octubre de 2011
martes 22 de marzo de 2011
PHP bug ?
<?php
$price = 125.99;
$dec = ($price - intval($price)) * 100;
$dec = (int) $dec;
echo $dec; // WTF?!
jueves 18 de noviembre de 2010
martes 5 de octubre de 2010
Campos LONGTEXT de MySQL y las Schema Migrations de CakePHP
Ultimamente ando un poco vago para escribir en este Blog, pero hoy me encontré con un caso/problema/solución que me parece que vale la pena compartir con uds.
Estaba trabajando con las migraciones de esquemas de CakePHP y me encontré con que el shell "schema" no distingue los tipos de columna LONGTEXT de MySQL, omitiendo las variantes de este tipo de columna y unificandolos a todos como 'text'.
He desarrollado una solución, más o menos elegante, para que los comandos "create" y "update" del schema shell reconozcan este tipo de dato. Todavía no encuentro una forma "no-intrusiva" de hacerlo para el comando "generate".
Básicamente, se trata de hacer un nuevo Data Source de CakePHP, pero en vez de extender la clase base, extender del DboMysql y solo implementar el array de tipos de datos del motor.
Para ello, como explica el manual, creo un nuevo archivo en app/models/datasources/dbo_custom_mysql.php con el siguiente contenido:
Esperemos que la gente de CakePHP ponga más esmero en resolver estas cositas que deberían estar listas desde varias versiones anteriores.
Estaba trabajando con las migraciones de esquemas de CakePHP y me encontré con que el shell "schema" no distingue los tipos de columna LONGTEXT de MySQL, omitiendo las variantes de este tipo de columna y unificandolos a todos como 'text'.
He desarrollado una solución, más o menos elegante, para que los comandos "create" y "update" del schema shell reconozcan este tipo de dato. Todavía no encuentro una forma "no-intrusiva" de hacerlo para el comando "generate".
Básicamente, se trata de hacer un nuevo Data Source de CakePHP, pero en vez de extender la clase base, extender del DboMysql y solo implementar el array de tipos de datos del motor.
Para ello, como explica el manual, creo un nuevo archivo en app/models/datasources/dbo_custom_mysql.php con el siguiente contenido:
Como ven, lo único que hago es extender el Datasource original de MySQL de CakePHP y agregarle un nuevo tipo de columna. Nada más. Luego, en su archivo app/config/database.php sólo deben indicar que su driver es 'custom_mysql' para hacer referencia a nuestro datasource. Y listo.
<?php
require_once(ROOT . '/cake/libs/model/datasources/dbo/dbo_mysql.php');
class DboCustomMysql extends DboMysql {
/**
* MySQL column definition
*
* @var array
*/
var $columns = array(
'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'),
'string' => array('name' => 'varchar', 'limit' => '255'),
'text' => array('name' => 'text'),
'longtext' => array('name' => 'longtext'),
'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'),
'float' => array('name' => 'float', 'formatter' => 'floatval'),
'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'),
'time' => array('name' => 'time', 'format' => 'H:i:s', 'formatter' => 'date'),
'date' => array('name' => 'date', 'format' => 'Y-m-d', 'formatter' => 'date'),
'binary' => array('name' => 'blob'),
'boolean' => array('name' => 'tinyint', 'limit' => '1')
);
}
Esperemos que la gente de CakePHP ponga más esmero en resolver estas cositas que deberían estar listas desde varias versiones anteriores.
lunes 26 de julio de 2010
Quick tip: _moz-rs-heading
Bueno, hoy me encontré con algo nuevo que vale la pena destacar.
Estoy empezando a transformar los sitios que desarrollo a HTML5. Sin mucha parafernaria, solo para ir testeando los casos de uso y acá me encontré uno peculiar.
Usando Firefox, me encuentro con un H2 que tiene un enlace en el DOM, el cual no está definido en el código.
El enlace, al inspeccionarlo con Firebug, se presenta similar al siguiente:
<a _moz-rs-heading="" href="">
Resultó ser culpa de un enlace mal cerrado anteriormente. Y parece ser que Firefox reestructura el DOM al encontrar errores como este en HTML5 y ha cerrado el enlace mal cerrado anteriormente al encontrar un punto en el que el contenido del enlace era inválido y lo ha continuado luego, abriendo esta etiqueta dentro de mi H2.
En fin, parece extraño, pero no se si juzgarlo como malo. En todo caso, es un comportamiento que la gente de Mozilla ha programado para este tipo de errores humanos en el código. Lo cual deja un DOM válido, como para que el layout se rompa lo menos posible, pero eso sí, si no tenemos en cuenta lo anterior, quizas sea un poco confuso al momento de encontrarlo... ahora ya saben!
Estoy empezando a transformar los sitios que desarrollo a HTML5. Sin mucha parafernaria, solo para ir testeando los casos de uso y acá me encontré uno peculiar.
Usando Firefox, me encuentro con un H2 que tiene un enlace en el DOM, el cual no está definido en el código.
El enlace, al inspeccionarlo con Firebug, se presenta similar al siguiente:
<a _moz-rs-heading="" href="">
Resultó ser culpa de un enlace mal cerrado anteriormente. Y parece ser que Firefox reestructura el DOM al encontrar errores como este en HTML5 y ha cerrado el enlace mal cerrado anteriormente al encontrar un punto en el que el contenido del enlace era inválido y lo ha continuado luego, abriendo esta etiqueta dentro de mi H2.
En fin, parece extraño, pero no se si juzgarlo como malo. En todo caso, es un comportamiento que la gente de Mozilla ha programado para este tipo de errores humanos en el código. Lo cual deja un DOM válido, como para que el layout se rompa lo menos posible, pero eso sí, si no tenemos en cuenta lo anterior, quizas sea un poco confuso al momento de encontrarlo... ahora ya saben!
martes 22 de diciembre de 2009
Apagar Windows Server desde Linux
Hoy me encontré con el dilema de tener 2 servidores y un solo UPS. La cuestión es que la interfaz USB del UPS está conectada a un servidor Ubuntu que corre el servicio apcupsd el cual me permite configurarlo para que el Ubuntu se apague cuando se está por agotar la batería del UPS.
Hasta acá todo en orden, la cuestión era apagar amablemente el otro servidor Windows 2003 también, antes de que se le acabe la batería al UPS. Para esto, el demonio apcupsd viene listo para que podamos escribir un programa que haga cualquier cosa antes de cualquiera de los eventos del UPS.
En nuestro caso, el evento en cuestión es el doshutdown que es el evento que apaga el servidor.
Para esto necesitamos crear un archivo llamado igual que el evento ubicado en el directorio /etc/apcupsd que es donde residen todos los scripts del demonio.
El script es:
que creo que es bastante clara... lo unico que vale aclarar es que el comando net está disponible en el paquete samba-common.
Recuerden que el script debe tener permisos de ejecución para funcionar.
Ahora el script se ejecutará siempre antes de que el apcupsd apague el servidor donde corre y así los 2 servidores serán apagados.
Hasta acá todo en orden, la cuestión era apagar amablemente el otro servidor Windows 2003 también, antes de que se le acabe la batería al UPS. Para esto, el demonio apcupsd viene listo para que podamos escribir un programa que haga cualquier cosa antes de cualquiera de los eventos del UPS.
En nuestro caso, el evento en cuestión es el doshutdown que es el evento que apaga el servidor.
Para esto necesitamos crear un archivo llamado igual que el evento ubicado en el directorio /etc/apcupsd que es donde residen todos los scripts del demonio.
El script es:
#!/bin/sh
net rpc shutdown -I 192.168.0.1 -U user%pass
que creo que es bastante clara... lo unico que vale aclarar es que el comando net está disponible en el paquete samba-common.
Recuerden que el script debe tener permisos de ejecución para funcionar.
Ahora el script se ejecutará siempre antes de que el apcupsd apague el servidor donde corre y así los 2 servidores serán apagados.
Suscribirse a:
Entradas (Atom)