Google APP Engine

Desde que salió la primera Beta de Google APP Engine (http://code.google.com/appengine/) me he descargado el App Engine SDK y realizado algunas pruebas para Foto DNG.

La idea es pasar la web de Foto DNG a los servidores de Google para poder beneficiarse de la escalabilidad de su sistema. Esto significa que no nos tendremos que preocupar de si tenemos 1 vista diaria o si recibimos 5 millones de visitas (Ojalá!), el sistema al estar distribuido entre las diferentes máquinas de Google se ocupa de su escalabilidad.

Las cuotas iniciales y gratuitas ofrecidas por el sistema son insuficientes para las necesidades de nuestra página, ya que 500Mb de espacio no son suficientes ni por asomo para los datos almacenados en la página y 1Mb. de tamaño máximo de archivo a todas luces queda muy lejos de nuestros requisitos pues las fotos enviadas al concurso pueden ser de hasta 2Mb. y los zip con la revista están cada uno entre 10 y 20Mb.

Pero la solución está en la versión de pago, ya que ayer anunciaron los precios que presumiblemente van a aplicar y que son los siguientes:

  • $0.10 – $0.12 per CPU core-hour
  • $0.15 – $0.18 per GB-month of storage
  • $0.11 – $0.13 per GB outgoing bandwidth
  • $0.09 – $0.11 per GB incoming bandwidth

Dichos precios podemos verlos en su blog en http://googleappengine.blogspot.com/ junto con los limites impuestos inicialmente en http://code.google.com/appengine/articles/quotas.html

El problema es que no podemos acogernos a esa versión de pago presumiblemente hasta comienzos del año que viene, además por ahora el lenguaje soportado es Python.

De momento vamos a comenzar con la migración de la página de Foto DNG a Python y llegado el momento valoraremos si damos el paso del actual servidor dedicado (que se nos queda pequeño) al Google App Engine. La inversión en tiempo para esta tarea será muy grande, aunque vistos los precios que se anuncian, gastaremos algo menos en los servicios de Hosting y ganaremos mucho en estabilidad.

Actualmente el ancho de banda consumido por las descargas de la revista varía desde los 45,95 GB. en el número 12 hasta los 144,73 GB. del número 2. El total de ancho de banda consumido sólo en las descargas hasta este momento es de 1.706,10 GB. Casi dos Terabytes de revista!.

Otro de los problemas (esperemos que temporales) es que no me puedo dar de alta de una nueva aplicación al no recibir el SMS de confirmación necesario para dicha alta, pero a la espera de la solución, podemos ir desarrollando en local con el APP Engine SDK.

Búsquedas en Foto DNG

Acabamos de implantar en la página de Foto DNG nuestro sistema de Búsquedas con la tecnología de Google ™ para ofrecer un nuevo servicio que busca tanto en la página principal de la revista http://www.fotodng.com como en este Blog http://blog.fotodng.com como en los foros http://foros.fotodng.com

Esperamos que esta nueva sección os pueda ser de utilidad, mientras seguimos con la búsqueda de nuevas opciones que mejoren su experiencia con Foto DNG.

Búsqueda en Foto DNG

Tercer concurso fotográfico Foto DNG

Ya está disponible el tercer concurso fotográfico Foto DNG (http://www.fotodng.com/concurso_08/) en esta ocasión contamos con los premios de nuestro patrocinador del concurso Robisa y que son los siguientes:

 

Ganador Ganador: Objetivo TAMRON AF70-300mm F/4-5.6 Di LD MACRO 1:2 dedicado para la marca, cortesía de Rodolfo Biber http://www.robisa.es/

 

 

 

Pimer Finalista Primer Finalista: Metz mecablitz 36 AF-4 dedicado para la marca, cortesía de Rodolfo Biber http://www.robisa.es/

 

 

 

 

Segundo Finalista Segundo Finalista: Kit de limpieza de sensores GREEN CLEAN SC-4200 para sensores APS-C, cortesía de Rodolfo Biber http://www.robisa.es/

 

 

 

 

Tercer Finalista Tercer Finalista: Tarjeta de memoria takeMS SD o CF de 4Gb., cortesía de Rodolfo Biber http://www.robisa.es/

 

 

 

 

 

 

 

 

Esperamos que la participación de este año, al menos iguale la de la edición anterior en la que recibimos 1.958 fotos.

Animaros a participar y no os olvidéis de leer previamente las Bases que podéis encontrar en http://www.fotodng.com/concurso_08/bases.php

Avisos al móvil de fallos del servidor (III)

Finalizo esta serie después de contaros la idea, los pasos a seguir en Google Calendar y mostraros el script, ahora sólo queda modificarlo con vuestro parámetros y programarlo para que se ejecute cada quince minutos (o modificar el tiempo de ejecución y su correspondiente parámetro).

Cuidado con poner bien las direcciones, no vaya a ser que pongáis una dirección errónea y se os llene el móvil de mensajes.

Para cualquier duda, podéis comentar la noticia y os responderé adecuadamente.

Espero que esta pequeña idea os pueda ser de utilidaz a webmasters.

Avisos al móvil de fallos del servidor (II)

Aquí os pongo el código php del script comentado en el post anterior (http://blog.fotodng.com/2008/05/avisos-al-mvil-de-fallos-del-servidor-i.html), en el siguiente post finalizaremos este ejemplo.

1
2
3 // (c) Carlos Longarela Abril 2008
4 // http://www.fotodng.com
5
6 function creaEventoCal ($cliente, $titulo = 'Evento por defecto'
7     $descrip='Evento por defecto de la funcion creaEventoCal', $donde = 'Madrid'
8     $FechaIni = null, $HoraIni = null
9     $FechaFin = null, $HoraFin = null, $tzOffset = '+02',
10     $metodo_recordatorio = 'sms'$tiempo_recordatorio=5){
11
12     if (empty($FechaIni)){
13         $FechaIni=date('Y-m-d');
14     }
15
16     if (empty($FechaFin)){
17         $FechaFin=date('Y-m-d');
18     }    
19
20     if (empty($HoraIni)){
21         $HoraIni=date('H');
22         $minutos=date('i')+7;
23         $minutos=str_pad($minutos, 2, '0', STR_PAD_LEFT);
24         $HoraIni.=':'.$minutos;
25     }      
26
27     if (empty($HoraFin)){
28         $HoraFin=$HoraIni;
29     }    
30         
31     $gc = new Zend_Gdata_Calendar($cliente);
32     $nuevaEntrada = $gc->newEventEntry();
33     $nuevaEntrada->title = $gc->newTitle(trim($titulo));
34     $nuevaEntrada->where  = array($gc->newWhere($donde));
35
36     $nuevaEntrada->content = $gc->newContent($descrip);
37     $nuevaEntrada->content->type = 'text';
38
39     $cuando = $gc->newWhen();
40     $cuando->startTime = "{$FechaIni}T{$HoraIni}:00.000{$tzOffset}:00";
41     $cuando->endTime = "{$FechaFin}T{$HoraFin}:00.000{$tzOffset}:00";
42     $nuevaEntrada->when = array($cuando);
43
44     //Creamos un nuevo evento de recordatorio
45     $recordatorio = $gc->newReminder();
46     $recordatorio->method = $metodo_recordatorio;
47     $recordatorio->minutes = $tiempo_recordatorio;
48
49     //Aplicamos el recordatorio a un evento cuando
50     $cuando->reminders = array($recordatorio);
51
52     $EntradaCreada = $gc->insertEvent($nuevaEntrada,CALENDARIO_SERVERS);
53
54     return $EntradaCreada->id->text;
55 }
56
57 function conecta_socket($ip, $puerto){
58     $texto=null;
59     if (($socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
60         $texto='FALLO en socket_create(); Causa: '.socket_strerror(socket_last_error())."n";
61         $GLOBALS['error']=true;
62         return $texto;
63     }else{
64         //Conexion a la IP en el puerto dado
65         $texto="Conectando a [$ip:$puerto]=>";
66         $res = @socket_connect($socket, $ip, $puerto);
67         if ($res === false) {
68             $texto.='FALLO en socket_connect(); Causa: '.socket_strerror(socket_last_error($socket))."n";
69             $GLOBALS['error']=true;
70             return $texto;
71         } else {
72             $texto.="OK.n";
73             return $texto;
74         }
75         socket_close($socket);        
76     }
77 }
78
79 function conecta_db($server_bd,$usuario_db,$clave_db,$db){
80     $texto=null;
81     $texto= "Conectando a [$server_bd -> $db]=>";
82     if (@mysql_connect($server_bd,$usuario_db,$clave_db)) {
83         if (@mysql_select_db($db)) {
84             $texto.="OK.n";
85             mysql_close();
86             return $texto;
87         }else{
88             $texto.=mysql_errno().": ".mysql_error();
89             $GLOBALS['error']=true;
90             mysql_close();
91             return $texto;
92         }
93     }else{
94         $texto.=mysql_errno().": ".mysql_error();
95         $GLOBALS['error']=true;
96         return $texto;
97     }    
98 }
99
100 //Permitir al script ejecutarse durante 2 minutos para esperar por las conexiones
101 set_time_limit(120);
102
103 //Volcar la salida al navegador para ir viendo los resultados
104 ob_implicit_flush();
105
106 //Incluimos el path de la liberia Zend Gdata
107 set_include_path('/ruta/liberia/gdata/library');
108
109 require_once 'Zend/Loader.php';
110 Zend_Loader::loadClass('Zend_Gdata');
111 Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
112 Zend_Loader::loadClass('Zend_Gdata_Calendar');
113 Zend_Loader::loadClass('Zend_Http_Client');
114
115 //Parametros de servidores
116 $ip = '11.11.11.11';
117 $ip_blog = gethostbyname('nombre.web.com');
118 $ip_site2 = gethostbyname('nombre2.web.com');
119 $puerto_web = 80;
120 $puerto_mysql = 3306;
121 $puerto_ssh = 22;
122
123 $server_bd=$ip;
124 $usuario_db='usuariobd';
125 $clave_db='clavebd';
126 $db='bd';
127
128 $texto=null;
129 $error=false;
130
131 //Parametros de la hora
132 date_default_timezone_set('Europe/Madrid');
133 $zona_horaria=date_default_timezone_get();
134 $dia=date('d');
135 $mes=date('m');
136 $anhio=date('Y');
137 $hora=date('H');
138 $minutos=date('i');
139 $fecha=$dia.'/'.$mes.'/'.$anhio.' '.$hora.':'.$minutos;
140
141 // Parametros para la autentificacion del cliente al calendario
142 $servicio = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
143 $usuario = "usuario.gmail.calendario@gmail.com";
144 $clave = "clave_usuario_gmail";
145 $id_calenadrio_servers='idcalendario@group.calendar.google.com';
146 $calenadrio_servers='http://www.google.com/calendar/feeds/'.$id_calenadrio_servers.'/private/full';
147 define('CALENDARIO_SERVERS', $calenadrio_servers);
148
149 header('Content-Type: text/plain; charset=utf-8');
150
151
152 // Creamos un cliente de autentificacion HTTP
153 try {
154     $cliente = Zend_Gdata_ClientLogin::getHttpClient($usuario, $clave, $servicio);
155 } catch (Zend_Gdata_App_AuthException $e) {
156     $texto='Error de autentificacion del usuario '.$usuario." en los servicios de Google.n"
157     die ((texto));
158 }
159
160 // Creamos una nueva instancia del servicio de Calendario
161 $servicio = new Zend_Gdata_Calendar($cliente);
162
163 //Intentamos las diferentes conexiones
164 $texto.=$fecha.' ('.$zona_horaria.")n";
165 //$texto.=conecta_socket($ip,$puerto_ssh);
166 $texto.=conecta_socket($ip,$puerto_web);
167 $texto.=conecta_socket($ip_blog,$puerto_web);
168 $texto.=conecta_socket($ip_site2,$puerto_web);
169 $texto.=conecta_socket($ip,$puerto_mysql);
170 $texto.=conecta_socket($ip_site2,$puerto_mysql);
171 $texto.=conecta_db($server_bd,$usuario_db,$clave_db,$db);
172
173 echo $texto;
174
175 if ($error===true){//Ha habido algun fallo
176     $titulo_evento='Fallo en el servidor '.$hora.':'.$minutos;    
177     $recordatorio='sms';
178     $envio_mail=true;
179 }else{//Todo correcto
180     $titulo_evento='Servidor OK '.$hora.':'.$minutos;
181     $recordatorio='none';
182     $envio_mail=false;    
183 }
184
185 creaEventoCal ($cliente, $titulo = $titulo_evento
186     $descrip=$texto, $donde = null
187     $FechaIni = null, $HoraIni = null
188     $FechaFin = null, $HoraFin = null, $tzOffset = '+02',
189     $metodo_recordatorio = $recordatorio$tiempo_recordatorio=5);
190
191 if ($envio_mail){
192     mail($usuario, $titulo_evento, $texto);    
193 }
194
195 ?>