Accéder à App Engine avec l'API Remote

Google Cloud CLI inclut un package remote_api qui vous permet d'accéder de manière transparente aux services App Engine à partir de n'importe quelle application Go. Par exemple, vous pouvez utiliser l'API Remote pour accéder à Datastore à partir d'une application s'exécutant sur votre ordinateur local ou à partir d'une autre de vos applications App Engine.

Pour afficher le contenu du package remote_api, consultez la documentation de référence sur le package remote_api.

Activer l'API Remote

Tout d'abord, ajoutez le gestionnaire url remote_api à votre fichier app.yaml. Exemple :

- url: /_ah/remote_api
  script: _go_app

Cela mappe l'URL /_ah/remote_api avec votre application Go. Seuls les administrateurs de l'application ont accès à cette URL par l'intermédiaire du gestionnaire de l'API Remote.

Importez ensuite le package remote_api dans l'un des packages de votre projet en ajoutant la ligne suivante à l'un de vos fichiers sources .go :

import _ "google.golang.org/appengine/remote_api"

Lors de l'initialisation du programme, le package remote_api enregistre un gestionnaire pour le chemin d'accès /_ah/remote_api. Le trait de soulignement dans la déclaration d'importation signifie "importer ce package, mais ne pas l'utiliser directement". Sans le trait de soulignement, vous recevriez un message d'erreur "importé mais non utilisé" lors de la compilation.

Enfin, déployez la mise à jour sur App Engine. Exemple :

gcloud app deploy app.yaml

Utiliser l'API Remote dans un client local

L'API Remote peut servir à écrire des applications locales qui utilisent les services App Engine et accèdent au datastore. Il est important de noter que l'utilisation de l'API Remote entraînera une utilisation du quota sur l'application à laquelle vous accédez.

Avant de commencer, assurez-vous que l’API Remote est activée dans votre application App Engine. L'application locale peut utiliser l'API Remote en créant un contexte avec remote_api.NewRemoteContext, et l'utiliser à la place du contexte App Engine normal dans tous les appels d'API.

// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package main

import (
	"log"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"

	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/remote_api"
)

func main() {
	const host = "<your-app-id>.appspot.com"

	ctx := context.Background()

	hc, err := google.DefaultClient(ctx,
		"https://www.googleapis.com/auth/appengine.apis",
		"https://www.googleapis.com/auth/userinfo.email",
		"https://www.googleapis.com/auth/cloud-platform",
	)
	if err != nil {
		log.Fatal(err)
	}

	remoteCtx, err := remote_api.NewRemoteContext(host, hc)
	if err != nil {
		log.Fatal(err)
	}

	q := datastore.NewQuery("Greeting").
		Filter("Date >=", time.Now().AddDate(0, 0, -7))

	log.Println(q.Count(remoteCtx))
}

Pour exécuter ce code, vous devez récupérer ces packages :

$ go get google.golang.org/appengine/...
$ go get golang.org/x/oauth2/...

Vous devez fournir le nom d'hôte de votre serveur et un client http.Client dans l'appel à NewRemoteContext. Le client http.Client fourni est responsable de la transmission des informations d'authentification requises dans chaque requête.

Dans l'exemple ci-dessus, le DefaultClient du package golang.org/x/oauth2/google fournit les identifiants OAuth 2 par l'intermédiaire des identifiants par défaut de l'application.

Limitations et bonnes pratiques

Le module remote_api ne recule devant rien pour faire en sorte, dans la mesure du possible, de se comporter exactement comme le datastore App Engine natif. Dans certains cas, cela se fait aux dépens de l'efficacité de certaines opérations. Rappelez-vous donc des quelques points suivants lorsque vous utilisez le module remote_api :

Chaque requête du datastore implique un certain temps de transfert

Étant donné que vous accédez au datastore via HTTP, la surcharge et la latence sont plus élevés qu'avec un accès en local. Pour réduire le temps de réponse et diminuer la charge, essayez de limiter le nombre de transferts que vous effectuez en groupant par lot les requêtes de type GET et les requêtes de type PUT, et en récupérant des lots d'entités auprès des requêtes. Cette consigne est valable non seulement pour le module remote_api, mais aussi pour l'utilisation du datastore en général, car une opération par lot n'est considérée que comme une opération de datastore unique.

Les requêtes vers le module remote_api utilisent des quotas

Étant donné que le module remote_api exploite le protocole HTTP, chaque appel au datastore que vous effectuez entraîne une utilisation du quota pour les requêtes HTTP, les octets entrants et sortants, ainsi que du quota de datastore habituel. Gardez cela à l'esprit si vous utilisez remote_api pour effectuer des mises à jour groupées.

Les limites d'1 Mo des API s'appliquent

Comme pour une exécution native, la limite d'1 Mo sur les requêtes et réponses d'API est toujours valable. Si vos entités sont particulièrement importantes, il se peut que vous deviez limiter le nombre que vous récupérez ou le répartir dans le temps pour rester en deçà de cette limite. Malheureusement, cela est en contradiction avec la réduction des temps de transfert. Le mieux est d'utiliser des lots les plus grands possibles sans dépasser les limites de taille des requêtes ou des réponses. Pour la plupart des entités, cependant, il y a peu de risques que cela pose problème.

Éviter l'itération des requêtes

Lorsque vous effectuez des itérations sur des requêtes, le SDK extrait les entités du datastore par lots de 20, récupérant un nouveau lot dès lors qu'il a utilisé les entités existantes. Étant donné que chaque lot doit être récupéré dans une requête distincte par remote_api, l'opération ne peut pas être efficace. À la place, remote_api exécute une requête entièrement nouvelle pour chaque lot, à l'aide de la fonctionnalité de décalage pour obtenir de meilleurs résultats.

Si vous connaissez le nombre d'entités qu'il vous faut, vous pouvez récupérer le tout dans une seule requête en demandant le nombre dont vous avez besoin :

Si vous ne savez pas de combien d'entités vous aurez besoin, vous pouvez utiliser les curseurs pour effectuer une itération efficace sur des ensembles de résultats volumineux. Cela vous permet également de contourner la limite de 1 000 entités, qui s'applique aux requêtes de datastore normales.

Les transactions sont moins efficaces

Pour la mise en œuvre de transactions via le module remote_api, ce dernier accumule des informations sur les entités récupérées dans la transaction, ainsi que les copies des entités qui ont été placées ou supprimées à l'intérieur de la transaction. Une fois que la transaction est validée, il envoie toutes ces informations au serveur App Engine, où il doit récupérer à nouveau toutes les entités qui ont été utilisées dans la transaction, vérifier qu'elles n'ont pas été modifiées, puis il doit appliquer et supprimer toutes les modifications effectuées par la transaction, et en effectuer un commit. En cas de conflit, le serveur effectue un rollback de la transaction et notifie le client, qui, à son tour, doit répéter tout le processus.

Cette approche fonctionne, et permet d'obtenir exactement les mêmes fonctionnalités que celles fournies par les transactions effectuées sur le datastore local, mais elle est inefficace. N'hésitez pas à utiliser des transactions lorsqu'elles sont nécessaires, mais en veillant à en limiter le nombre et la complexité afin de conserver une bonne efficacité.