Python 2 ya no es compatible con la comunidad. Te recomendamos que migres las apps de Python 2 a Python 3.

Cómo se manejan las solicitudes

ID de región

REGION_ID es un código abreviado que Google asigna en función de la región que seleccionas cuando creas tu app. El código no corresponde a un país o provincia, aunque algunos ID de región puedan parecer similares a los códigos de país y provincia de uso común. Incluir REGION_ID.r en las URL de App Engine es opcional para las apps existentes, y pronto será obligatorio para todas las aplicaciones nuevas.

A fin de garantizar una transición sin problemas, estamos actualizando App Engine con lentitud para usar los ID de región. Si aún no actualizamos tu proyecto de Google Cloud, no verás un ID de región para la app. Dado que el ID es opcional para las apps existentes, no necesitas actualizar las URL ni realizar otros cambios una vez que el ID de región esté disponible para las apps existentes.

Obtén más información acerca de los ID de región.

En este documento se describe cómo tu aplicación de App Engine recibe solicitudes y envía respuestas. Para obtener más detalles, consulta la referencia de encabezados de solicitud y respuestas.

Si tu aplicación usa servicios, puedes dirigir solicitudes a un servicio específico o a una versión específica de ese servicio. Para obtener más información sobre cómo direccionar el servicio, consulta Cómo enrutar solicitudes.

Cómo controlar las solicitudes

La aplicación se encarga de iniciar un servidor web y controlar las solicitudes. Puedes usar cualquier marco de trabajo web que esté disponible para tu lenguaje de desarrollo.

App Engine ejecuta varias instancias de tu aplicación, y cada una tiene su propio servidor web para manejar solicitudes. Estas pueden enrutarse a cualquier instancia, por lo que las solicitudes consecutivas del mismo usuario no necesariamente se envían a la misma instancia. Una instancia puede manejar varias solicitudes al mismo tiempo. La cantidad de instancias se puede ajustar de forma automática a medida que cambia el tráfico. También puedes cambiar la cantidad de solicitudes simultáneas que puede controlar una instancia si configuras el elemento max_concurrent_requests en el archivo app.yaml.

Cuando App Engine recibe una solicitud web para la aplicación, llama a la secuencia de comandos del controlador que corresponde a la URL, como se describe en el archivo de configuración app.yaml de la aplicación. El entorno de ejecución de Python 2.7 admite el estándar WSGI y el estándar CGI para la retrocompatibilidad. Se prefiere WSGI, y algunas características de Python 2.7 no funcionan sin él. La configuración de los controladores de secuencia de comandos de la aplicación determina si una solicitud se maneja con WSGI o CGI.

La siguiente secuencia de comandos de Python responde a una solicitud con un encabezado HTTP y el mensaje Hello, World!.

import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.write('Hello, World!')

app = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)

Para despachar varias solicitudes a cada servidor web en paralelo, agrega un threadsafe: true a su archivo app.yaml. Las solicitudes simultáneas no están disponibles si algún controlador de secuencia de comandos usa CGI.

Cuotas y límites

App Engine asigna recursos a tu aplicación de manera automática a medida que el tráfico aumenta. Sin embargo, esto se limita con las siguientes restricciones:

  • App Engine reserva la capacidad de ajuste de escala automático para aplicaciones con latencia baja a fin de que la aplicación responda a las solicitudes en menos de un segundo. Las aplicaciones con latencia muy alta, como las de más de un segundo por solicitud para varias solicitudes, y con capacidad de procesamiento alta requieren asistencia nivel Plata, Oro o Platino. Los clientes con este nivel de asistencia pueden comunicarse con su representante de asistencia para solicitar el aumento de sus límites de capacidad de procesamiento.

  • Las aplicaciones estrechamente vinculadas a la CPU también pueden incurrir en alguna latencia adicional para compartir recursos de manera eficaz con otras aplicaciones en el mismo servidor. Las solicitudes para archivos estáticos están exentas de estos límites de capacidad de latencia.

Cada solicitud que entra a la aplicación se tiene en cuenta para los límites de Solicitudes. Los datos enviados en respuesta a una solicitud se tienen en cuenta para el límite de Ancho de banda de salida (facturable).

Tanto las solicitudes HTTP como las HTTPS (seguras) se tienen en cuenta para los límites de Solicitudes, Ancho de banda de entrada (facturable) y Ancho de banda de salida (facturable). La página Detalles de cuota de Cloud Console también informa las Solicitudes seguras, el Ancho de banda de entrada seguro y el Ancho de banda saliente seguro como valores separados. Solo se tienen en cuenta las solicitudes HTTPS para estos valores. Para obtener más información, consulta la página de Cuotas.

Los siguientes límites se aplican específicamente al uso de los controladores de solicitudes:

Límite Importe
tamaño de la solicitud 32 megabytes
tamaño de la respuesta 32 megabytes
Tiempo de espera de la solicitud depende del tipo de escalamiento que use la app
cantidad total máxima de archivos (archivos estáticos y de la app) 10,000 en total
1,000 por directorio
tamaño máximo de un archivo de la aplicación 32 megabytes
tamaño máximo de un archivo estático 32 megabytes
tamaño total máximo de todos los archivos estáticos y de la aplicación el primer gigabyte es gratis
$0.026 por gigabyte por mes después del primer gigabyte

Límites de la respuesta

Las respuestas dinámicas tienen un límite de 32 MB. Si un controlador de secuencia de comandos genera una respuesta superior a este límite, el servidor envía una respuesta vacía con un código de estado 500 “Error interno del servidor”. Esta limitación no se aplica a las respuestas que entregan datos desde Blobstore o Cloud Storage.

Encabezados de solicitud

Una solicitud HTTP nueva incluye los encabezados HTTP que envía el cliente. Por motivos de seguridad, los proxies intermedios limpian o modifican algunos encabezados antes de que lleguen a la aplicación.

Para obtener más información, consulta la referencia de Encabezados de solicitud.

Respuestas a solicitudes

App Engine llama a la secuencia de comandos del controlador con una RequestRequest y espera a que la secuencia de comandos regrese. Todos los datos escritos en el flujo de salida estándar se envían como la respuesta HTTP.

Se aplican límites a la respuesta que generas y la respuesta se puede modificar antes de que regrese al cliente.

Para obtener más información, consulta la referencia de respuestas a solicitudes.

Respuestas a transmisión

App Engine no admite la transmisión de respuestas, donde los datos se envían en fragmentos graduales al cliente mientras se procesa una solicitud. Todos los datos de tu código se recopilan como se describió anteriormente y se envían como una respuesta HTTP simple.

Compresión de la respuesta

Si el cliente envía encabezados HTTP con la solicitud original que indican que el cliente puede aceptar contenido comprimido (en formato Gzip), App Engine comprime automáticamente los datos de respuesta del controlador y adjunta los encabezados de respuesta adecuados. Usa los encabezados de solicitud Accept-Encoding y User-Agent para determinar si el cliente puede recibir respuestas comprimidas de manera confiable.

Los clientes personalizados pueden indicar la posibilidad de recibir respuestas comprimidas si especifican los encabezados Accept-Encoding y User-Agent con el valor gzip. El Content-Type de la respuesta también se usa para determinar si es adecuado usar la compresión. Por lo general, los tipos de contenido basado en texto están comprimidos, mientras que los tipos de contenido binario no lo están.

Cuando App Engine comprime las respuestas automáticamente, el encabezado Content-Encoding se agrega a la respuesta.

Especifica un plazo de solicitud

App Engine está optimizado para aplicaciones con solicitudes de corta duración, que son por lo general las que tardan unos cientos de milisegundos. Una app eficiente responde con rapidez a la mayoría de las solicitudes. Si una app no puede hacerlo, no escalará bien con la infraestructura de App Engine.

Todas las solicitudes a tu app deben mostrar una respuesta dentro del tiempo de espera máximo de la solicitud. Si tu app no responde dentro del tiempo de espera, App Engine interrumpe el controlador de solicitudes. El entorno de ejecución de Python interrumpe el controlador de solicitudes mediante la generación de un DeadlineExceededError desde el paquete google.appengine.runtime. Si el controlador de solicitudes no detecta esta excepción, como ocurre con todas las excepciones no detectadas, el entorno de ejecución mostrará al cliente un error de servidor HTTP 500.

El controlador de solicitudes puede detectar este error para personalizar la respuesta. El entorno de ejecución le da al controlador de solicitudes un poco más de tiempo (menos de un segundo) después de generar la excepción para preparar una respuesta personalizada.

class TimerHandler(webapp2.RequestHandler):
    def get(self):
        from google.appengine.runtime import DeadlineExceededError

        try:
            time.sleep(70)
            self.response.write('Completed.')
        except DeadlineExceededError:
            self.response.clear()
            self.response.set_status(500)
            self.response.out.write(
                'The request did not complete in time.')

Si tu controlador no muestra una respuesta o genera una excepción antes del segundo plazo, el controlador se cierra y se muestra una respuesta de error predeterminada.

Logging

El servidor web de App Engine captura todo lo que la secuencia de comandos del controlador escribe en la transmisión de salida estándar para la respuesta a la solicitud web. También captura todo lo que la secuencia de comandos del controlador escribe en el flujo de error estándar y lo almacena como datos de registro. A cada solicitud se le asigna un request_id, un identificador único global según la hora de inicio de la solicitud. Los datos de registro de tu aplicación se pueden ver en Cloud Console con Cloud Logging.

El entorno de ejecución de Python de App Engine incluye una asistencia especial para el módulo de registro de la biblioteca estándar de Python que te ayuda a comprender los conceptos de registro, como los niveles de registro (“depuración”, “información”, “advertencia”, “error”, “crítico”).

import logging

import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        logging.debug('This is a debug message')
        logging.info('This is an info message')
        logging.warning('This is a warning message')
        logging.error('This is an error message')
        logging.critical('This is a critical message')

        try:
            raise ValueError('This is a sample value error.')
        except ValueError:
            logging.exception('A example exception log.')

        self.response.out.write('Logging example.')

app = webapp2.WSGIApplication([
    ('/', MainPage)
], debug=True)

Entorno

El entorno de ejecución establece automáticamente varias variables de entorno. puedes configurar más en app.yaml. De las variables configuradas automáticamente, algunas son especiales para App Engine, mientras que otras son parte de los estándares WSGI o CGI. El código de Python puede acceder a estas variables con el diccionario os.environ.

Las siguientes variables del entorno son específicas de App Engine:

  • CURRENT_VERSION_ID: la versión principal y secundaria de la aplicación actualmente en ejecución, como "X.Y". El número de la versión principal (“X”) se especifica en el archivo app.yaml de la app. El número de la versión secundaria ("Y") se configura automáticamente cuando cada versión de la aplicación se sube a App Engine. En el servidor web de desarrollador, la versión secundaria siempre es "1".

  • AUTH_DOMAIN: El dominio que se usa para autenticar usuarios con la API de usuarios. Las apps alojadas en appspot.com tienen un AUTH_DOMAIN de gmail.com y aceptan cualquier Cuenta de Google. Las aplicaciones alojadas en un dominio personalizado tienen un AUTH_DOMAIN igual al dominio personalizado.

  • INSTANCE_ID: contiene el ID de la instancia de frontend que maneja una solicitud. El ID es una string hexadecimal (por ejemplo, 00c61b117c7f7fd0ce9e1325a04b8f0df30deaaf). Un administrador que accedió puede usar el ID en una URL: https://INSTANCE_ID-dot-VERSION_ID-dot-SERVICE_ID-dot-PROJECT_ID.REGION_ID.r.appspot.com. La solicitud se enrutará a esa instancia de frontend específica. Si la instancia no puede manejar la solicitud, muestra un 503 de inmediato.

Las siguientes variables del entorno son parte de los estándares WSGI y CGI, con un comportamiento especial en App Engine:

  • SERVER_SOFTWARE: En el servidor web de desarrollador, este valor es "Desarrollo/X.Y", en el que "X.Y" es la versión del entorno de ejecución. Cuando se ejecuta en App Engine, este valor es "Google App Engine/X.Y.Z".

Las variables del entorno adicionales se configuran de acuerdo con el estándar WSGI o CGI. Para obtener más información sobre estas variables, consulta el estándar WSGI o el estándar CGI, según corresponda.

También puedes establecer variables de entorno en el archivo app.yaml:

env_variables:
  DJANGO_SETTINGS_MODULE: 'myapp.settings'

El siguiente controlador de solicitud webapp2 muestra todas las variables del entorno visibles para la aplicación en el navegador:

class PrintEnvironmentHandler(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        for key, value in os.environ.iteritems():
            self.response.out.write(
                "{} = {}\n".format(key, value))

ID de solicitud

En el momento de la solicitud, puedes guardar el ID de solicitud, que es único para esa solicitud. El ID de solicitud se puede usar más adelante para buscar los registros de esa solicitud en Cloud Logging.

El siguiente código de muestra señala cómo obtener el ID de solicitud en el contexto de una solicitud:

class RequestIdHandler(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        request_id = os.environ.get('REQUEST_LOG_ID')
        self.response.write(
            'REQUEST_LOG_ID={}'.format(request_id))

Almacenamiento en caché de la aplicación

El entorno de ejecución de Python almacena en caché módulos importados entre solicitudes en un único servidor web, de manera similar a como una aplicación Python independiente carga un módulo solo una vez, incluso si el módulo es importado por varios archivos. Dado que los controladores WSGI son módulos, se almacenan en caché entre solicitudes. Las secuencias de comandos del controlador CGI solo se almacenan en caché si proporcionan una rutina main() de lo contrario, se cargan para cada solicitud.

El almacenamiento en caché de la app proporciona un beneficio importante en el tiempo de respuesta. Recomendamos que todas las secuencias de comandos del controlador CGI utilicen una rutina main(), como se describe a continuación.

Las importaciones se almacenan en caché

Para mayor eficiencia, el servidor web mantiene los módulos importados en la memoria y no los vuelve a cargar ni los vuelve a evaluar en solicitudes posteriores a la misma aplicación en el mismo servidor. La mayoría de los módulos no inicializan ningún dato global o tienen otros efectos secundarios cuando se importan, por lo que el 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 evalúa para cada solicitud, la aplicación debe adaptarse a este comportamiento de almacenamiento en caché.

Almacenamiento en caché de controladores CGI

Puedes indicar a App Engine que almacene en caché la secuencia de comandos del controlador CGI, además de los módulos importados. Si la secuencia de comandos del 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 servidor web determinado evalúa la secuencia de comandos normalmente. Para solicitudes posteriores, App Engine llama a la función main() en el entorno almacenado en caché.

Para almacenar en caché una secuencia de comandos del controlador, App Engine debe poder llamar a main() sin argumentos. Si la secuencia de comandos del 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 secuencia de comandos completa para cada solicitud.

Mantener el código de Python analizado en la memoria ahorra tiempo y permite respuestas más rápidas. El almacenamiento en caché del entorno global también tiene otros usos potenciales:

  • Expresiones regulares compiladas. Todas las expresiones regulares se analizan y almacenan en un formulario compilado. Puedes almacenar expresiones regulares compiladas en variables globales, luego, usar el almacenamiento en caché de la aplicación para reutilizar los objetos compilados entre solicitudes.

  • Objetos GqlQuery. La string de consulta GQL se analiza cuando se crea el objeto GqlQuery. Reutilizar un objeto GqlQuery con vinculación de parámetros y el método bind() es más rápido que reconstruir el objeto cada vez. Puedes almacenar un objeto GqlQuery con la vinculación de parámetros para los valores en una variable global, luego, reutilizarlo vinculando nuevos valores de parámetros a cada solicitud.

  • Configuración y archivos de datos. Si tu aplicación carga y analiza los datos de configuración de un archivo, puede retener los datos analizados en la memoria para evitar tener que volver a cargar el archivo con cada solicitud.

La secuencia de comandos del controlador debe llamar a main() cuando se importa. App Engine espera que la importación de la secuencia de comandos llame a main(), por lo que App Engine no la llama cuando carga el controlador de solicitudes por primera vez en un servidor.

El almacenamiento en caché de apps con main() proporciona una mejora significativa en el tiempo de respuesta del controlador CGI. Lo recomendamos para todas las aplicaciones que usan CGI.