Google Code disponible en: English - Español - 日本語 - 한국어 - Português - Pусский - 中文(简体) - 中文(繁體)
App Engine ejecuta el código de tu aplicación Python mediante un intérprete de Python cargado previamente en un entorno seguro de "zona de pruebas". Mediante la interacción con este entorno, tu aplicación recibe solicitudes web, realiza el trabajo y envía respuestas.
App Engine sabe cómo utilizar el entorno de tiempo de ejecución, cuando utilizas la herramienta appcfg.py del SDK Python con un archivo de configuración denominado app.yaml. Puedes seleccionar el entorno de tiempo de ejecución Python mediante los siguientes elementos de configuración:
runtime: python api_version: 1
El primer elemento, runtime, selecciona el entorno de tiempo de ejecución Python. Por el momento, App Engine sólo admite el entorno de tiempo de ejecución python.
El segundo elemento, api_version, selecciona la versión del entorno de tiempo de ejecución Python que se va a utilizar. Por el momento, App Engine sólo dispone de la versión 1 de Python. Si el equipo de App Engine necesitara realizar algún cambio en el entorno no compatible con el código existente, tendría que hacerlo con un identificador de versión nuevo. Tu aplicación continuará necesitando la versión seleccionada hasta que modifiques la configuración api_version la subas.
Para obtener más información acerca de app.yaml y appcfg.py, consulta los artículos Configuración de aplicaciones Python y Subida de aplicaciones.
Cuando App Engine recibe una solicitud web para tu aplicación, App Engine ejecuta la secuencia de comandos de controlador que se corresponde con la URL, como se describe en el archivo de configuración app.yaml de la aplicación. App Engine utiliza el estándar CGI para comunicar los datos de solicitud al controlador y recibir la respuesta.
App Engine utiliza varios servidores web para ejecutar tu aplicación y ajustará automáticamente el número de servidores en uso para procesar las solicitudes de una forma segura. Una determinada solicitud se puede enviar a cualquier servidor, que no tiene que ser el mismo servidor que procesó una solicitud anterior procedente del mismo usuario.
El servidor determina qué secuencia de comandos de controlador Python debe ejecutar mediante la comparación de la URL de la solicitud con los patrones de URL del archivo de configuración de la aplicación. A continuación ejecuta el controlador en un entorno CGI relleno con los datos de la solicitud. Como se describe en el estándar CGI, el servidor coloca los datos de la solicitud en variables de entorno y en el flujo de entrada estándar. La secuencia de comandos realiza las acciones correspondientes en la solicitud y, a continuación, prepara una respuesta y la coloca en el flujo de salida estándar.
La mayoría de las aplicaciones utilizan una biblioteca para analizar las solicitudes CGI y devolver respuestas CGI como, por ejemplo, el módulo cgi de la biblioteca estándar de Python o un framework web que conozca el protocolo CGI (por ejemplo, webapp). Para obtener información detallada sobre las variables de entorno y el formato de los datos del flujo de entrada, consulta la documentación de CGI.
En la siguiente secuencia de comandos de controlador de ejemplo aparece un mensaje en el navegador del usuario. Imprime un encabezado HTTP que identifica el tipo y el contenido del mensaje en el flujo de salida estándar.
print "Content-Type: text/plain" print "" print "Hello, world!"
App Engine recopila todos los datos que la secuencia de comandos de controlador de solicitud escribe en el flujo de salida estándar y, a continuación, espera a la salida de la secuencia de comandos. Tras la salida de la secuencia de comandos, todos los datos de salida se envían al usuario.
App Engine no es compatible con el envío de datos al navegador del usuario antes de la salida del controlador. Algunos servidores web utilizan esta técnica para "hacer fluir" los datos hacia el navegador del usuario durante un período de tiempo en respuesta a una única solicitud. Esta técnica de flujo no es compatible con App Engine.
Si el cliente envía encabezados HTTP en la solicitud que indiquen que el cliente puede aceptar contenido comprimido (gzip), App Engine comprimirá automáticamente los datos de respuesta y adjuntará los encabezados de respuesta correspondientes. Utiliza tanto los encabezados de solicitud Accept-Encoding como User-Agent para determinar si el cliente puede recibir respuestas comprimidas de forma segura. Los clientes personalizados fuerzan la compresión del contenido mediante la especificación de los encabezados Accept-Encoding y User-Agent con un valor "gzip".
Un controlador de solicitudes dispone de una cantidad de tiempo limitada para generar y devolver una respuesta a una solicitud, en general, 30 segundos aproximadamente. Una vez alcanzado el plazo, el controlador de solicitudes se interrumpe.
El entorno de tiempo de ejecución Python interrumpe el controlador de solicitudes mediante la generación de la excepción DeadlineExceededError del paquete google.appengine.runtime. Si el controlador de solicitud no detecta esta ni otras excepciones, el entorno de tiempo de ejecución devuelve al cliente un error de servidor HTTP 500.
El controlador de solicitud puede detectar este error para personalizar la respuesta. El entorno de tiempo de ejecución proporciona al controlador de solicitud un poco de más tiempo (menos de un segundo), tras establecer la excepción, para preparar una respuesta personalizada.
from google.appengine.runtime import DeadlineExceededError
class MainPage(webapp.RequestHandler):
def get(self):
try:
# Do stuff...
except DeadlineExceededError:
self.response.clear()
self.response.set_status(500)
self.response.out.write("This operation could not be completed in time...")
Si no ha devuelto ninguna respuesta ni ha generado ninguna excepción tras la conclusión del segundo plazo, se finaliza el controlador y se devuelve una respuesta de error predeterminada.
Mientras que la respuesta a una solicitud puede tardar hasta 30 segundos, App Engine se optimiza para aplicaciones con solicitudes breves, normalmente aquellas que tardan unos cien milisegundos. Una aplicación eficaz responde rápidamente a la mayoría de las solicitudes. Una aplicación que no lo hace, no se ampliará correctamente con la infraestructura de App Engine.
Para permitir a App Engine distribuir solicitudes para aplicaciones a través de varios servidores web y evitar que una aplicación interfiera en otra, la aplicación se ejecuta en un entorno de "zona de pruebas" restringido. En este entorno, la aplicación puede ejecutar datos de consulta, almacenamiento y código en el almacén de datos de App Engine, utilizar el correo de App Engine, la extracción de URL y los servicios de usuarios, y examinar las solicitudes web del usuario y preparar la respuesta.
Una aplicación App Engine no puede:
El entorno de tiempo de ejecución Python utiliza Python versión 2.5.2.
Todo el código del entorno de tiempo de ejecución Python debe ser Python puto y no incluir ninguna extensión C ni cualquier otro código que se pueda compilar.
El entorno incluye la biblioteca estándar de Python. Algunos módulos se han desactivado porque sus funciones principales no son compatibles con App Engine como, por ejemplo, la interconexión o la escritura en el sistema de archivos. Además, el módulo os está disponible, pero algunas funciones no compatibles se encuentran inhabilitadas. Si se intenta importar un módulo no compatible o utilizar una función no compatible, se generará una excepción.
Algunos módulos de la biblioteca estándar se han sustituido o se han personalizado para que funcionen con App Engine. Por ejemplo:
TemporaryFile, que se ha aliado con StringIO.Además de la biblioteca estándar Python y las bibliotecas de App Engine, el entorno de tiempo de ejecución incluye las siguientes bibliotecas externas:
Puedes incluir otras bibliotecas Python puras en tu aplicación. Para ello, coloca el código en el directorio de la aplicación. Si creas un enlace simbólico al directorio de un módulo en el directorio de tu aplicación, appcfg.py seguirá el enlace e incluirá el módulo en la aplicación.
La ruta incluida en el módulo Python incluye el directorio raíz de la aplicación (el directorio que contiene el archivo app.yaml). Los módulos creados en el directorio raíz de tu aplicación están disponibles a través una ruta desde el directorio raíz. No olvides crear archivos __init__.py en los subdirectorios; de este modo, Python reconocerá los subdirectorios como paquetes.
El entorno de tiempo de ejecución Python almacena en caché módulos importados entre solicitudes en un servidor web de forma similar al modo en que una aplicación Python independiente carga un módulo una sola vez aunque varios archivos importen ese módulo. Si una secuencia de comandos de controlador proporciona una rutina main(), el entorno de tiempo de ejecución también almacena en caché la secuencia de comandos. De lo contrario, se carga la secuencia de comandos de controlador con cada solicitud.
El almacenamiento en caché de aplicaciones proporciona una ventaja significativa en lo que respecta al tiempo de respuesta. Recomendamos que todas las aplicaciones utilicen una rutina main(), tal como se describe a continuación.
Para una mayor eficiencia, el servidor web conserva los módulos importados en memoria y no vuelve a cargarlos ni evaluarlos en solicitudes posteriores a la misma aplicación llevadas a cabo en el mismo servidor. La mayoría de los módulos no inicializan ningún dato global ni presentan otros efectos secundarios cuando se importan, por lo que su almacenamiento en caché no cambia el comportamiento de la aplicación.
Si la aplicación importa un módulo que depende del módulo que se está evaluando para cada solicitud, la aplicación debe acomodar este comportamiento de almacenamiento en caché.
En el siguiente ejemplo se demuestra cómo se almacena en caché un módulo importado. Dado que mymodule sólo se importa una vez para un único servidor web, el parámetro mymodule.counter global sólo se inicializa en 0 con la primera solicitud procesada por el servidor. Las solicitudes posteriores utilizan el valor de la solicitud anterior.
### mymodule.py counter = 0 def increment(): global counter counter += 1 return counter ### myhandler.py import mymodule print "Content-Type: text/plain" print "" print "My number: " + str(mymodule.increment())
Esta acción da como resultado My number: #, donde # es el número de veces que el servidor web que procesó la solicitud ha llamado a este controlador.
Puedes indicar a App Engine que almacene por sí mismo la secuencia de comandos de controlador en caché, además de los módulos importados. Si la secuencia de comandos de controlador define una función llamada main(), la secuencia de comandos y su entorno global se almacenarán en caché como un módulo importado. La primera solicitud de la secuencia de comandos en un determinado servidor web evalúa normalmente la secuencia de comandos. Para las solicitudes posteriores, App Engine ejecuta la función main() en el entorno almacenado en caché.
Para almacenar una secuencia de comandos de controlador en caché, App Engine debe poder ejecutar main() sin argumentos. Si la secuencia de comandos de controlador no define una función main() o la función main() requiere argumentos (que no tienen valores predeterminados), App Engine carga y evalúa la totalidad de la secuencia de comandos con cada solicitud.
Si mantienes en memoria el código Python analizado, ahorrarás tiempo y obtendrás respuestas más rápidas. El almacenamiento en caché del entorno global presenta otros posibles usos:
Al importarse, la secuencia de comandos de controlador debería ejecutar main(). App Engine espera que la importación de la secuencia de comandos ejecute main(), por lo que App Engine no realizará su ejecución al cargar en el servidor el controlador de solicitud por primera vez.
Con el siguiente ejemplo se realiza la misma acción que con el ejemplo anterior, utilizando el almacenamiento en caché del entorno global de la secuencia de comandos de controlador:
### myhandler.py # A global variable, cached between requests on this web server. counter = 0 def main(): global counter counter += 1 print "Content-Type: text/plain" print "" print "My number: " + str(counter) if __name__ == "__main__": main()
Nota: ten cuidado de no "filtrar" información específica de un usuario entre solicitudes. Evita las variables globales a menos que se recomiende el almacenamiento en caché e inicializa los datos específicos de una solicitud dentro de la rutina main().
El almacenamiento en caché de aplicaciones con main() ofrece una mejora significativa en el tiempo de respuesta de la aplicación. Lo recomendamos para todas las aplicaciones.
El servidor web de App Engine captura todo lo que la secuencia de comandos del controlador escribe en el flujo de salida estándar como respuesta a la solicitud web. También captura todo lo que la secuencia de comandos del controlador escribe en el flujo de errores estándar y lo almacena como datos de registro. Puedes ver y analizar los datos de registro de tu aplicación con la consola de administración o descargarlos mediante appcfg.py request_logs.
El entorno de tiempo de ejecución Python de App Engine presenta una compatibilidad especial con el módulo logging de la biblioteca estándar Python para comprender conceptos de registro, tales como los niveles de registro ("debug", "info", "warning", "error", "critical").
import logging
from google.appengine.api import users
from google.appengine.ext import db
user = users.get_current_user()
if user:
q = db.GqlQuery("SELECT * FROM UserPrefs WHERE user = :1", user)
results = q.fetch(2)
if len(results) > 1:
logging.error("more than one UserPrefs object for user %s", str(user))
if len(results) == 0:
logging.debug("creating UserPrefs object for user %s", str(user))
userprefs = UserPrefs(user=user)
userprefs.put()
else:
userprefs = results[0]
else:
logging.debug("creating dummy UserPrefs for anonymous user")
El entorno de ejecución incluye diversas variables de entorno útiles para la aplicación. Algunas de ellas son especiales de App Engine, mientras que otras forman parte del estándar CGI. El código Python puede acceder a estas variables a través del diccionario os.environ.
Las siguientes variables de entorno son específicas de App Engine:
APPLICATION_ID: la ID de la aplicación actualmente en ejecución.CURRENT_VERSION_ID: la versión principal y secundaria de la aplicación actualmente en ejecución, por ejemplo "X.Y". El número de versión principal ("X") se especifica en el archivo app.yaml de la aplicación. El número de versión secundaria ("Y") se establece automáticamente cuando se sube cada versión de la aplicación en App Engine. En el servidor web de desarrollo, la versión principal es siempre "1". AUTH_DOMAIN: el dominio utilizado para autenticar usuarios con el API de usuarios. Las aplicaciones alojadas en appspot.com tienen un dominio AUTH_DOMAIN de gmail.com y aceptan cualquier cuenta de Google. Las aplicaciones alojadas en un dominio personalizado que utilice Google Apps tienen un dominio AUTH_DOMAIN igual al dominio personalizado.Las siguientes variables de entorno forman parte del estándar CGI, con un comportamiento especial en App Engine:
SERVER_SOFTWARE: en el servidor web de desarrollo, este valor es "Development/X.Y", donde "X.Y" es la versión del tiempo de ejecución. Las variables de entorno adicionales se definen de acuerdo con el estándar CGI. Para obtener más información sobre estas variables, consulta el estándar CGI.
Sugerencia: el siguiente controlador de solicitudes de webapp muestra todas las variables de entorno visible para la aplicación en el navegador:
from google.appengine.ext import webapp
import os
class PrintEnvironmentHandler(webapp.RequestHandler):
def get(self):
for name in os.environ.keys():
self.response.out.write("%s = %s<br />\n" % (name, os.environ[name]))
Todas las solicitudes de entrada de la aplicación se contabilizan en la cuota de Solicitudes.
Los datos recibidos como parte de una solicitud se contabilizan en la cuota de ancho de banda de entrada (facturable). Los datos enviados como respuesta a una solicitud se contabilizan en la cuota de ancho de banda de salida (facturable).
Tanto las solicitudes HTTP como HTTPS (seguras) se contabilizan en las cuota de solicitudes, en la de ancho de banda de entrada (facturable) y en la de ancho de banda de salida (facturable). La página de detalles de cuota de la consola de administración también informa sobre solicitudes seguras, ancho de banda de entrada seguro y ancho de banda de salida seguro como valores independientes únicamente con finalidad informativa. Sólo las solicitudes HTTPS se contabilizan en estos valores.
El tiempo de procesamiento de CPU empleado en ejecutar un controlador de solicitudes se contabiliza en la cuota de Tiempo de CPU (facturable).
Para obtener más información sobre cuotas, consulta la sección Cuotas y la sección "Detalles de cuota" de la consola de administración.
Además de las cuotas, al controlador de solicitudes se le aplican los siguientes límites:
| Límite | Valor |
|---|---|
| tamaño de la solicitud | 10 megabytes |
| tamaño de la respuesta | 10 megabytes |
| duración de la solicitud | 30 segundos |
| solicitudes dinámicas simultáneas | 30 |
| número máximo de archivos de aplicación | 1.000 |
| número máximo de archivos estáticos | 1.000 |
| tamaño máximo de un archivo de aplicación | 10 megabytes |
| tamaño máximo de un archivo estático | 10 megabytes |
| tamaño total máximo de todos los archivos estáticos y de aplicación | 150 megabytes |
* Una aplicación puede procesar alrededor de 30 solicitudes dinámicas activas simultáneamente. Esto significa que, una aplicación cuya media de tiempo de procesamiento de solicitudes del servidor sea de 75 milisegundos podrá presentar hasta (1.000 ms/segundo / 75 ms/solicitud) * 30 = 400 solicitudes/segundo sin conllevar latencia adicional. Las aplicaciones que tienen un límite de CPU considerable pueden conllevar latencia adicional en solicitudes prolongadas a fin de crear espacio para otras aplicaciones que compartan los mismos servidores. Las solicitudes para archivos estáticos no se ven influidas por este límite.