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.

App Engine exécute plusieurs instances de votre application, chacune d'elles disposant de son propre serveur Web pour le traitement des requêtes. Étant donné que chaque requête peut être acheminée vers n'importe quelle instance, les requêtes consécutives provenant d'un même utilisateur ne sont pas nécessairement envoyées à la même instance. Une instance peut traiter plusieurs requêtes simultanément. Le nombre d'instances peut être ajusté automatiquement en fonction de l'évolution du trafic. Vous pouvez également modifier le nombre de requêtes simultanées qu'une instance peut gérer en définissant l'élément max_concurrent_requests dans le fichier app.yaml.

Lorsque App Engine reçoit une requête Web pour votre application, il appelle le script de gestionnaire correspondant à l'URL, comme décrit dans le fichier de configuration app.yaml de l'application. L'environnement d'exécution Python 2.7 est compatible avec les normes WSGI et CGI pour la rétrocompatibilité. Il est préférable d'utiliser WSGI, sinon certaines fonctionnalités de Python 2.7 ne fonctionneront pas. La configuration des gestionnaires de script de votre application détermine si une requête est gérée à l'aide de WSGI ou de CGI.

Le script Python ci-dessous permet de répondre à une requête avec un en-tête HTTP et le message 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)

Pour répartir plusieurs requêtes en parallèle sur chaque serveur Web, marquez votre application comme threadsafe (à fil sécurisé) en ajoutant threadsafe: true à votre fichier app.yaml. Les requêtes simultanées ne sont pas disponibles si un gestionnaire de script utilise CGI.

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 appelle le script de gestionnaire avec un objet Request, puis attend qu'il renvoie un résultat. Toutes les données écrites dans le flux de sortie standard sont envoyées sous forme de réponse HTTP.

Certaines limites s'appliquent à la réponse que vous générez. 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.

Lorsque 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. L'exécution du gestionnaire de requêtes est interrompue lorsqu'il arrive à expiration. L'environnement d'exécution Python interrompt le gestionnaire de requêtes en générant une erreur DeadlineExceededError à partir du package google.appengine.runtime. Si le gestionnaire de requêtes n'intercepte pas cette exception, l'environnement d'exécution renvoie une erreur de serveur HTTP 500 au client, comme pour toutes les exceptions non interceptées.

Le gestionnaire de requêtes peut intercepter cette erreur pour personnaliser la réponse. L'environnement d'exécution accorde au gestionnaire de requêtes un délai un peu plus long (moins d'une seconde) après la génération de l'exception pour lui laisser le temps de préparer une réponse personnalisée.

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 le gestionnaire n'a pas renvoyé de réponse ni généré d'exception à l'expiration du deuxième délai, il est arrêté. Un message d'erreur par défaut est alors renvoyé.

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.

Pour connaître les causes courantes d'erreurs DeadlineExceededError et les solutions de contournement proposées, consultez les informations sur les erreurs DeadlineExceededError.

Journalisation

Le serveur Web App Engine capture tout ce que le script de gestionnaire écrit dans le flux de sortie standard pour la réponse à la requête Web. Il récupère également tout ce que le script de gestionnaire écrit dans le flux d'erreur standard et le stocke sous forme de données de journal. Chaque requête se voit attribuer un identifiant global unique request_id, basé sur son heure de début. Les données de journal de votre application peuvent être visualisées dans la console GCP à l'aide de Stackdriver Logging.

L'environnement d'exécution Python d'App Engine offre une assistance particulière pour le module de journalisation de la bibliothèque standard Python afin d'expliciter des concepts tels que les niveaux de journalisation ("debug", "info", "warning", "error", "critical").

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)

Environnement

L'environnement d'exécution définit automatiquement plusieurs variables d'environnement. Vous pouvez toutefois en configurer d'autres dans le fichier app.yaml. Certaines des variables définies automatiquement sont propres à App Engine, tandis que d'autres font partie des normes WSGI ou CGI. Le code Python peut accéder à ces variables à l'aide du dictionnaire os.environ.

Les variables d'environnement suivantes sont spécifiques à App Engine :

  • CURRENT_VERSION_ID : versions principale et secondaire de l'application en cours d'exécution (par exemple, "X.Y"). Le numéro de la version principale ("X") est spécifié dans le fichier app.yaml de l'application. Le numéro de la version secondaire ("Y") est défini automatiquement lorsque chaque version de l'application est importée dans App Engine. Sur le serveur de développement Web, la version secondaire correspond toujours à "1".

  • AUTH_DOMAIN : domaine utilisé pour l'authentification des utilisateurs avec l'API Users. Les applications hébergées sur appspot.com sont associées au domaine AUTH_DOMAIN gmail.com et acceptent n'importe quel compte Google. Le paramètre AUTH_DOMAIN des applications hébergées sur un domaine personnalisé correspond à ce dernier.

  • INSTANCE_ID : contient l'ID de l'instance frontend traitant une requête. Cet ID correspond à une chaîne hexadécimale (par exemple, 00c61b117c7f7fd0ce9e1325a04b8f0df30deaaf). Un administrateur connecté peut utiliser l'ID dans une URL : http://[INSTANCE_ID].myApp.appspot.com/. La requête sera alors acheminée vers cette instance frontend spécifique. Si l'instance ne peut pas traiter la requête, elle renvoie immédiatement l'erreur 503.

Les variables d'environnement ci-dessous font partie des normes WSGI et CGI. Elles ont un comportement particulier dans App Engine :

  • SERVER_SOFTWARE : dans le serveur Web de développement, cette valeur est "Development/X.Y", où "X.Y" correspond à la version de l'environnement d'exécution. Lors de l'exécution sur App Engine, cette valeur est "Google App Engine/X.Y.Z".

Des variables d'environnement supplémentaires sont définies conformément à la norme WSGI ou CGI. Pour en savoir plus sur ces variables, reportez-vous à la norme WSGI ou à la norme CGI, le cas échéant.

Vous pouvez également spécifier des variables d'environnement dans le fichier app.yaml :

env_variables:
  DJANGO_SETTINGS_MODULE: 'myapp.settings'

Le gestionnaire de requêtes webapp2 ci-dessous affiche toutes les variables d'environnement visibles par l'application dans le navigateur :

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 requête

Au moment de la requête, vous pouvez enregistrer l'ID de requête, qui est unique à cette requête. L'ID de requête peut être utilisé ultérieurement pour rechercher les journaux de cette requête dans Stackdriver Logging.

L'exemple de code ci-dessous montre comment obtenir l'ID d'une requête dans le contexte de cette dernière :

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

Mise en cache des applications

L'environnement d'exécution Python met en cache les modules importés entre les requêtes effectuées sur un même serveur Web, de la même manière qu'une application Python autonome charge un module une seule fois même s'il est importé par plusieurs fichiers. Les gestionnaires WSGI étant des modules, ils sont mis en cache entre les requêtes. Les scripts de gestionnaire CGI ne sont mis en cache que s'ils fournissent une routine main(), sinon ils sont chargés pour chaque requête.

La mise en cache des applications offre un avantage significatif en termes de réduction du temps de réponse. Il est préférable que tous les scripts de gestionnaire CGI utilisent une routine main(), comme indiqué ci-dessous.

Les importations sont mises en cache

Pour plus d'efficacité, le serveur Web conserve en mémoire les modules importés, mais ne les recharge pas et ne les réévalue pas lors des requêtes suivantes adressées à la même application sur le même serveur. La plupart des modules n'initialisent aucune donnée globale et n'ont aucun autre effet secondaire lors de leur importation. Par conséquent, leur mise en cache ne modifie pas le comportement de l'application.

Si votre application importe un module en fonction de son évaluation lors de chaque requête, elle doit s'adapter à ce comportement de mise en cache.

Mettre en cache des gestionnaires CGI

Vous pouvez demander à App Engine de mettre en cache le script de gestionnaire CGI lui-même, en plus des modules importés. Si le script définit une fonction nommée main(), il est mis en cache avec son environnement global comme un module importé. La première requête exécutée pour le script sur un serveur Web donné l'évalue normalement. Pour les requêtes ultérieures, App Engine appelle la fonction main() dans l'environnement mis en cache.

Pour mettre en cache un script de gestionnaire, App Engine doit pouvoir appeler main() sans argument. Si le script de gestionnaire ne définit pas de fonction main() ou si la fonction main() requiert des arguments (sans valeur par défaut), App Engine charge et évalue le script dans son intégralité pour chaque requête.

La conservation en mémoire du code Python analysé permet de gagner du temps et de réduire les temps de réponse. La mise en cache de l'environnement global offre d'autres possibilités d'utilisation :

  • Expressions régulières compilées : toutes les expressions régulières sont analysées et stockées sous une forme compilée. Vous pouvez stocker des expressions régulières compilées dans des variables globales, puis utiliser la mise en cache de l'application pour réutiliser les objets compilés entre les requêtes.

  • Objets GqlQuery : la chaîne de requête GQL est analysée lors de la création de l'objet GqlQuery. Il est plus rapide de réutiliser un objet GqlQuery avec une liaison de paramètre et la méthode bind() que de recréer l'objet à chaque fois. Vous pouvez stocker un objet GqlQuery avec une liaison de paramètre pour les valeurs présentes dans une variable globale, puis le réutiliser en liant de nouvelles valeurs de paramètre pour chaque requête.

  • Fichiers de configuration et de données : si votre application charge et analyse les données de configuration d'un fichier, elle peut conserver en mémoire les données analysées pour éviter d'avoir à recharger le fichier pour chaque requête.

Le script de gestionnaire doit appeler main() lorsqu'il est importé. App Engine s'attend à ce que l'importation du script appelle main(). App Engine ne l'appelle donc pas lors du premier chargement du gestionnaire de requêtes sur un serveur.

La mise en cache des applications avec main() offre une amélioration significative du temps de réponse de votre gestionnaire CGI. Nous recommandons de procéder de la sorte pour toutes les applications utilisant CGI.

Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Environnement standard App Engine pour Python 2