Mode de traitement des requêtes

Ce document décrit comment votre application App Engine reçoit des requêtes et envoie des réponses. Pour en savoir plus, consultez la documentation de référence sur les en-têtes de requêtes et les réponses.

Si votre application utilise des services, vous pouvez adresser des requêtes à un service spécifique ou à une version particulière de ce service. Pour en savoir plus sur l'adressage des services, consultez la page Mode de routage des requêtes.

Traiter des requêtes

Votre application est responsable du démarrage d'un serveur Web et du traitement des requêtes. Vous pouvez utiliser n'importe quel framework Web disponible pour votre langage de développement.

Lorsque le service App Engine reçoit une requête Web pour votre application, il appelle le servlet correspondant à l'URL, comme décrit dans le fichier web.xml du répertoire WEB-INF/ de l'application. Il est compatible avec les spécifications de l'API Java Servlet 2.5 ou 3.1, qui permet de fournir les données de la requête au servlet et d'accepter les données de réponse.

App Engine exécute plusieurs instances de votre application, et chaque instance dispose de son propre serveur Web pour le traitement des requêtes. Toute requête pouvant être acheminée vers n'importe quelle instance, les requêtes consécutives du même utilisateur ne sont pas nécessairement envoyées à la même instance. Le nombre d'instances peut être ajusté automatiquement en fonction de l'évolution du trafic.

Par défaut, chaque serveur Web ne traite qu'une requête à la fois. Pour distribuer plusieurs requêtes à chaque serveur en parallèle, votre application doit être "threadsafe". Pour ce faire, ajoutez l'élément <threadsafe>true</threadsafe> au fichier appengine-web.xml.

L'exemple de classe de servlet ci-dessous affiche un message simple dans le navigateur de l'utilisateur.

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");
  }
}

Quotas et limites

App Engine alloue automatiquement des ressources à votre application lorsque le trafic augmente. Toutefois, les restrictions suivantes s'appliquent :

  • App Engine réserve une capacité de scaling automatique pour les applications à faible latence, qui répondent aux requêtes en moins d'une seconde. Les applications à latence très élevée (par exemple, de plus d'une seconde par requête pour un grand nombre de requêtes) et à haut débit nécessitent une formule d'assistance Silver, Gold ou Platinum. Les clients bénéficiant de ce niveau d'assistance peuvent demander une augmentation de leurs limites de débit en contactant leur représentant de l'équipe d'assistance.

  • En outre, le temps de latence des applications fortement dépendantes des processeurs peut augmenter de manière à permettre le partage efficace des ressources avec les autres applications hébergées sur les mêmes serveurs. Aucune limite de latence n'est appliquée aux requêtes de fichiers statiques.

Chaque requête entrante vers l'application est prise en compte dans la limite des requêtes. Les données envoyées en réponse à une requête sont comptabilisées dans la limite de bande passante sortante (facturable).

Les requêtes HTTP et HTTPS (sécurisées) sont comptabilisées dans les limites de requêtes, de bande passante entrante (facturable) et de bande passante sortante (facturable). Sur la page Quotas de la console GCP, les requêtes sécurisées, la bande passante entrante sécurisée et la bande passante sortante sécurisée sont également indiquées sous forme de valeurs distinctes à des fins d'information. Seules les requêtes HTTPS sont comptabilisées dans ces valeurs. Pour en savoir plus, consultez la page Quotas.

Les limites ci-dessous s'appliquent spécifiquement à l'utilisation de gestionnaires de requêtes :

Limite Volume
Taille d'une requête 32 Mo
Taille d'une réponse 32 Mo
Durée d'une requête 60 secondes
Nombre total de fichiers, au maximum (fichiers d'application et fichiers statiques) 10 000 au total
1 000 par répertoire
Taille maximale d'un fichier d'application 32 Mo
Taille maximale d'un fichier statique 32 Mo
Taille maximale du total des fichiers d'application et des fichiers statiques Premier gigaoctet gratuit
0,026 $ par gigaoctet et par mois au-delà du premier gigaoctet

Limites de réponses

La taille des réponses dynamiques est limitée à 32 Mo. Si un gestionnaire de script génère une réponse dépassant cette limite, le serveur renvoie une réponse vide avec le code d'état 500 indiquant une erreur interne du serveur. Cette limite ne s'applique pas aux réponses qui diffusent des données provenant du service Blobstore ou de Cloud Storage.

En-têtes de requêtes

Une requête HTTP entrante inclut des en-têtes HTTP envoyés par le client. Pour des raisons de sécurité, certains en-têtes sont nettoyés ou modifiés par des serveurs proxy intermédiaires avant d'atteindre l'application.

Pour en savoir plus, consultez la documentation de référence sur les en-têtes de requête.

Réponses aux requêtes

App Engine transmet au servlet un objet de requête et un objet de réponse, puis attend que le servlet complète l'objet de réponse et le renvoie. Les données de l'objet de réponse sont alors envoyées à l'utilisateur.

Certaines limites s'appliquent à la réponse que vous générez et celle-ci peut être modifiée avant d'être renvoyée au client.

Pour en savoir plus, consultez la documentation de référence sur les réponses aux requêtes.

Réponses en flux continu

App Engine n'accepte pas les réponses en flux continu dans lesquelles les données sont envoyées au client par blocs incrémentiels pendant le traitement d'une requête. Toutes les données de votre code sont collectées comme indiqué ci-dessus et envoyées sous la forme d'une réponse HTTP unique.

Compression de la réponse

Si le client envoie avec la requête initiale des en-têtes HTTP indiquant qu'il peut accepter du contenu compressé (avec gzip), le service App Engine compresse automatiquement les données de réponse du gestionnaire et joint les en-têtes de réponse appropriés. Il utilise les en-têtes de requête Accept-Encoding et User-Agent pour déterminer si le client peut recevoir des réponses compressées de manière fiable.

Les clients personnalisés peuvent indiquer qu'ils sont en mesure de recevoir des réponses compressées en spécifiant les en-têtes Accept-Encoding et User-Agent avec la valeur gzip. L'en-tête Content-Type de la réponse permet également de déterminer si la compression est appropriée. En général, les contenus de type texte sont compressés, alors que ceux de type binaire ne le sont pas.

Lorsqu'App Engine compresse automatiquement les réponses, l'en-tête Content-Encoding est ajouté à ces dernières.

Spécifier un délai de requête

Un gestionnaire de requêtes dispose d'un temps limité pour générer et renvoyer une réponse à une requête. Ce délai est généralement de l'ordre de 60 secondes. Une fois ce dernier dépassé, l'exécution du gestionnaire de requêtes est interrompue. L'environnement d'exécution Java arrête le servlet en générant une exception com.google.apphosting.api.DeadlineExceededException. S'il n'existe aucun gestionnaire de requêtes pour intercepter cette exception, l'environnement d'exécution renvoie une erreur de serveur HTTP 500 au client.

S'il existe un gestionnaire de requêtes et que l'exception DeadlineExceededException est interceptée, l'environnement d'exécution lui donne le temps nécessaire (moins d'une seconde) pour préparer une réponse personnalisée. Si le gestionnaire de requêtes prend plus d'une seconde après la génération de l'exception pour préparer une réponse personnalisée, une erreur HardDeadlineExceededError est renvoyée.

L'exception DeadlineExceededExceptions et l'erreur HardDeadlineExceededErrors forcent l'arrêt de la requête et supprime l'instance.

Pour savoir combien de temps il reste avant l'expiration du délai, l'application peut importer com.google.apphosting.api.ApiProxy et appeler ApiProxy.getCurrentEnvironment().getRemainingMillis(). Cela s'avère utile si elle prévoit de commencer un travail susceptible de prendre trop de temps. Si vous savez que le traitement d'une unité de travail dure cinq secondes, mais que la méthode getRemainingMillis() prend moins de temps, il est inutile de démarrer cette unité de travail.

Le délai nécessaire pour obtenir une réponse à une requête peut atteindre 60 secondes. Toutefois, App Engine est optimisé pour les applications dont les requêtes sont de courte durée (quelques centaines de millisecondes, en général). Pour être efficace, une application doit répondre rapidement à la majorité des requêtes. Si tel n'est pas le cas, elle n'est pas adaptée à l'infrastructure App Engine.

Consultez la page Gérer les erreurs DeadlineExceededErrors pour connaître les causes courantes d'erreurs DeadlineExceededError et les solutions de contournement proposées.

Journaliser des données

Votre application peut écrire des informations dans les journaux de l'application à l'aide de java.util.logging.Logger. Vous pouvez afficher les données de journalisation de votre application dans la console GCP à l'aide de Stackdriver Logging. Chaque requête journalisée se voit attribuer un ID de requête, un identifiant global unique basé sur l'heure de début de la requête. La console GCP reconnaît les niveaux de journalisation de la classe Logger et affiche de manière interactive des messages à différents niveaux.

Tout ce que le servlet écrit dans le flux de résultat standard (System.out) et dans le flux d'erreur standard (System.err) est collecté par App Engine et enregistré dans les journaux de l'application. Les lignes écrites dans le flux de résultat standard sont journalisées au niveau "INFO" et les lignes écrites dans le flux d'erreur standard sont journalisées au niveau "AVERTISSEMENT". Tout framework de journalisation (tel que log4j) qui écrit dans les flux de résultat ou d'erreur standards est accepté. Cependant, lors d'un contrôle plus détaillé de l'affichage du niveau de journalisation dans la console GCP, le framework de journalisation doit utiliser un adaptateur 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.");
    // ...
  }
}

Le SDK Java d'App Engine comprend un fichier modèle logging.properties dans le répertoire appengine-java-sdk/config/user/. Pour l'utiliser, copiez-le dans votre répertoire WEB-INF/classes (ou ailleurs dans l'archive WAR), puis la propriété système java.util.logging.config.file dans "WEB-INF/logging.properties" (ou le chemin d'accès que vous choisissez, en fonction de la racine de l'application). Vous pouvez définir les propriétés système dans le fichier appengine-web.xml, comme suit :

<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>

Le servlet consigne les messages à l'aide du niveau de journalisation INFO (via log.info()). Le niveau par défaut est WARNING, lequel supprime les messages INFO du résultat. Pour changer le niveau de journalisation, modifiez le fichier logging.properties. Consultez l'application Guestbook Form pour obtenir un exemple spécifique de définition des niveaux de journalisation.

Environnement

Toutes les propriétés système et les variables d'environnement sont propres à votre application. La définition d'une propriété système n'affecte que la façon dont votre application interprète cette propriété, mais pas celle dont la VM Java l'interprète.

Vous pouvez définir les propriétés système et les variables d'environnement de votre application dans le descripteur de déploiement.

App Engine définit plusieurs propriétés système qui identifient l'environnement d'exécution :

  • La propriété com.google.appengine.runtime.environment correspond à l'environnement "Production" lors de l'exécution sur App Engine et à l'environnement "Development" lors de l'exécution sur le serveur de développement.

    Outre la méthode System.getProperty(), vous pouvez accéder aux propriétés système à l'aide de notre API sécurisée comme suit :

    if (SystemProperty.environment.value() ==
        SystemProperty.Environment.Value.Production) {
        // The app is running on App Engine...
    }
    
  • L'élément com.google.appengine.runtime.version est l'ID de version de l'environnement d'exécution, tel que "1.3.0". Vous pouvez obtenir la version en appelant la méthode suivante : String version = SystemProperty.version.get();

  • L'élément com.google.appengine.application.id est l'ID application. Vous pouvez l'obtenir en appelant la méthode suivante : String ID = SystemProperty.applicationId.get();

  • L'élément com.google.appengine.application.version correspond à la version majeure et mineure du service d'application en cours d'exécution, au format "X.Y". Le numéro de version majeure ("X") est spécifié dans le fichier appengine-web.xml du service. Le numéro de la version mineure ("Y") est défini automatiquement lorsque chaque version de l'application est importée sur App Engine. Vous pouvez obtenir l'ID en appelant la méthode suivante : String ID = SystemProperty.applicationVersion.get();

    Sur le serveur Web de développement, la version majeure renvoyée est toujours la version du service par défaut et la version mineure est toujours "1".

Le service App Engine définit également les propriétés système suivantes lorsqu'il initialise la VM Java sur un serveur d'applications :

  • 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 d'instances

Vous pouvez récupérer l'ID de l'instance qui traite une requête à l'aide de ce code :

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

Dans l'environnement de production, un administrateur connecté peut utiliser l'ID d'une URL : http://[INSTANCE_ID].myApp.appspot.com/. La requête est alors acheminée vers cette instance spécifique. Si l'instance ne peut pas traiter la requête, elle renvoie immédiatement l'erreur 503.

ID de requête

Au moment de la requête, vous pouvez enregistrer l'ID de requête, un identifiant unique qui peut être utilisé ultérieurement pour mettre en corrélation une requête et les journaux qui y sont associés.

Le code suivant montre comment obtenir l'ID de requête dans le contexte d'une requête :

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