Cómo manejar solicitudes

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 la aplicación usa servicios, puedes direccionar 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 programación.

Cuando App Engine recibe una solicitud web para la aplicación, invoca al servlet que corresponde a la URL, como se describe en el archivo web.xml en el directorio WEB-INF/ de la aplicación. Admite las especificaciones de la API del Servlet de Java 2.5 o 3.1 para proporcionar los datos de solicitud al servlet y aceptar los datos de respuesta.

App Engine ejecuta varias instancias de la aplicación, y cada una tiene su propio servidor web para controlar las solicitudes. Las solicitudes se pueden enrutar a cualquier instancia, por lo que las solicitudes consecutivas del mismo usuario no necesariamente se envían a la misma instancia. La cantidad de instancias se puede ajustar de forma automática a medida que el tráfico cambia.

De forma predeterminada, cada servidor web procesa solo una solicitud a la vez. Si deseas enviar múltiples solicitudes a cada servidor web en paralelo, agrega un elemento <threadsafe>true</threadsafe> al archivo appengine-web.xml a fin de marcar tu aplicación como segura para procesos.

La siguiente clase de servlet de ejemplo muestra un mensaje simple en el navegador del usuario.

Java 8

// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required.
@WebServlet(name = "requests", description = "Requests: Trivial request", urlPatterns = "/requests")
public class RequestsServlet extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    resp.setContentType("text/plain");
    resp.getWriter().println("Hello, world");
  }
}

Java 7

public class RequestsServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws IOException {
    resp.setContentType("text/plain");
    resp.getWriter().println("Hello, world");
  }
}

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 a las siguientes restricciones:

  • App Engine reserva la capacidad de escalamiento 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, por ejemplo, las de más de un segundo por solicitud para varias solicitudes y 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 GCP Console también informa las solicitudes seguras, el ancho de banda de entrada seguro y el ancho de banda de salida seguro como valores individuales para fines informativos. Solo las solicitudes HTTPS se tienen en cuenta 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
duración de la solicitud 60 segundos
cantidad total máxima de archivos (archivos estáticos y de la aplicación) 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 (1) gigabyte es gratuito
$0.026 por gigabyte al mes después del primer (1) gigabyte

Límites de la respuesta

Las respuestas dinámicas se limitan a 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 al servlet con un objeto de solicitud y un objeto de respuesta y, luego, espera que el servlet propague el objeto de respuesta y lo muestre. Cuando el servlet lo muestra, se envían al usuario los datos en el objeto de respuesta.

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

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

Respuestas a transmisión

App Engine no admite respuestas a transmisión cuando 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 indica 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. El servicio 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 la compresión es adecuada. 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 automáticamente las respuestas, se agrega el encabezado Content-Encoding a la respuesta.

Cómo especificar un plazo de solicitud

Un controlador de solicitudes tiene un tiempo limitado para generar y mostrar una respuesta a una solicitud, normalmente alrededor de 60 segundos. Una vez alcanzado el plazo, el controlador de solicitudes se interrumpe. El entorno de ejecución de Java interrumpe al servlet y genera com.google.apphosting.api.DeadlineExceededException. Si el controlador de solicitudes no detecta esta excepción, el entorno de ejecución mostrará un error de servidor HTTP 500 al cliente.

Si el controlador de solicitudes detecta la DeadlineExceededException, el entorno de ejecución le da tiempo (menos de un segundo) al controlador para preparar una respuesta personalizada. Si el controlador de solicitudes tarda más de un segundo después de que se genera la excepción para preparar una respuesta personalizada, se generará un HardDeadlineExceededError.

Tanto las DeadlineExceededExceptions como los HardDeadlineExceededErrors forzarán la finalización de la solicitud y eliminarán la instancia.

Para saber cuánto tiempo resta antes de que se cumpla el plazo, la aplicación puede importar com.google.apphosting.api.ApiProxy y llamar a ApiProxy.getCurrentEnvironment().getRemainingMillis(). Esto resulta muy útil si la aplicación planifica iniciar algún trabajo que podría llevar demasiado tiempo. Si sabes que lleva cinco segundos procesar una unidad de trabajo, pero getRemainingMillis() muestra menos tiempo, no tiene sentido iniciar esa unidad de trabajo.

Aunque una solicitud puede tardar hasta 60 segundos en mostrar una respuesta, App Engine está optimizado para aplicaciones con solicitudes de corta duración, normalmente las que tardan unos cientos de milisegundos. Una aplicación eficiente responde rápidamente a la mayoría de las solicitudes. Si una aplicación no puede hacerlo, no escalará bien con la infraestructura de App Engine.

Consulta Cómo proceder ante DeadlineExceededErrors para conocer las causas comunes de DeadlineExceededError y las soluciones alternativas recomendadas.

Registro

La aplicación puede escribir la información en sus registros con java.util.logging.Logger. Se pueden ver los datos de registro de la aplicación en GCP Console con Stackdriver Logging. A cada solicitud registrada se le asigna un ID de solicitud, un identificador único global basado en la hora de inicio de la solicitud. La GCP Console puede reconocer los niveles de registro de la clase Logger y mostrar mensajes de forma interactiva en diferentes niveles.

App Engine captura lo que el servlet escribe en la transmisión de salida estándar (System.out) y en la transmisión de errores estándar (System.err), y todo esto se registra en los registros de la aplicación. Las líneas escritas en la transmisión de salida estándar se registran en el nivel "INFO" y las líneas escritas en la transmisión de errores estándar se registran en el nivel "WARNING". Cualquier marco de trabajo de registro (como log4j) que registre en las transmisiones de salida o de errores funcionará. Sin embargo, para obtener un control más preciso del nivel de registro que se visualiza en GCP Console, el marco de trabajo de registro debe usar un adaptador java.util.logging.

Java 8

// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required.
@WebServlet(
    name = "RequestLogging",
    description = "Requests: Logging example",
    urlPatterns = "/requests/log"
)
public class LoggingServlet extends HttpServlet {

  private static final Logger log = Logger.getLogger(LoggingServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    log.info("An informational message.");
    log.warning("A warning message.");
    log.severe("An error message.");
    // ...
  }
}

Java 7

public class LoggingServlet extends HttpServlet {
  private static final Logger log = Logger.getLogger(LoggingServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
    log.info("An informational message.");
    log.warning("A warning message.");
    log.severe("An error message.");
    // ...
  }
}

El SDK de Java en App Engine incluye un archivo de plantilla logging.properties en el directorio appengine-java-sdk/config/user/. Para usarlo, copia el archivo en tu directorio WEB-INF/classes (o en cualquier otra parte del WAR) y, luego, la propiedad del sistema java.util.logging.config.file en "WEB-INF/logging.properties" (o en cualquier ruta que selecciones, relativa a la raíz de la aplicación). Puedes configurar las propiedades del sistema en appengine-web.xml de la siguiente manera:

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    ...

    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
    </system-properties>

</appengine-web-app>

El servlet registra los mensajes con el nivel de registro INFO (con log.info()). El nivel de registro predeterminado es WARNING, lo que elimina los mensajes INFO de la salida. Para cambiar el nivel de registro, edita el archivo logging.properties. Consulta la aplicación Formulario de Guestbook para obtener un ejemplo específico sobre cómo configurar los niveles de registro.

Entorno

Todas las propiedades del sistema y las variables del entorno son privadas para tu aplicación. Configurar una propiedad del sistema solo afecta a la vista de la propiedad de la aplicación y no a la vista de JVM.

Puedes configurar las propiedades del sistema y las variables del entorno para la aplicación en el descriptor de implementación.

App Engine configura varias propiedades del sistema que identifican el entorno de ejecución:

  • com.google.appengine.runtime.environment es "Production" cuando se ejecuta en App Engine y "Development" cuando se ejecuta en el servidor de programación.

    Además de usar System.getProperty(), puedes acceder a las propiedades del sistema mediante nuestra API type-safe. A continuación, se muestra un ejemplo:

    if (SystemProperty.environment.value() ==
        SystemProperty.Environment.Value.Production) {
        // The app is running on App Engine...
    }
    
  • com.google.appengine.runtime.version es el ID de la versión del entorno de ejecución, por ejemplo, "1.3.0". Puedes invocar lo siguiente para obtener la versión: String version = SystemProperty.version.get();

  • com.google.appengine.application.id es el ID de la aplicación. Puedes invocar lo siguiente para obtener el ID: String ID = SystemProperty.applicationId.get();

  • com.google.appengine.application.version es la versión principal y secundaria del servicio de la aplicación actualmente en ejecución, por ejemplo, "X.Y". El número de la versión principal ("X") se especifica en el archivo appengine-web.xml del servicio. 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. Puedes invocar lo siguiente para obtener el ID: String ID = SystemProperty.applicationVersion.get();

    En el servidor web de desarrollador, la versión principal siempre es la versión predeterminada del servicio y la versión secundaria siempre es "1".

App Engine también configura las siguientes propiedades del sistema cuando inicializa JVM en un servidor de la aplicación:

  • file.separator
  • path.separator
  • line.separator
  • java.version
  • java.vendor
  • java.vendor.url
  • java.class.version
  • java.specification.version
  • java.specification.vendor
  • java.specification.name
  • java.vm.vendor
  • java.vm.name
  • java.vm.specification.version
  • java.vm.specification.vendor
  • java.vm.specification.name
  • user.dir

ID de la instancia

Puedes administrar una solicitud con este código para recuperar el ID de la instancia:

com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.instance.id")

En el entorno de producción, un administrador con acceso puede usar el ID en una URL: http://[INSTANCE_ID].myApp.appspot.com/. La solicitud se enrutará a esa instancia específica. Si la instancia no puede controlar la solicitud, muestra un error 503 inmediato.

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 relacionar una solicitud con los registros de esa solicitud.

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

com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.runtime.request_log_id")

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno estándar de App Engine para Java 8