API Remote pour les anciens services groupés

Le SDK Java inclut une bibliothèque appelée API Remote qui vous permet d'accéder en toute transparence aux services App Engine depuis n'importe quelle application Java. Par exemple, vous pouvez vous servir de cette API pour accéder à un datastore de production depuis une application qui s'exécute sur votre ordinateur local. Vous avez également la possibilité d'utiliser l'API Remote afin d'accéder au datastore d'une application App Engine à partir d'une autre application App Engine.

Configurer l'API Remote sur le serveur

Le composant de serveur de l'API Remote est un servlet Java qui fait partie de l'environnement d'exécution App Engine pour Java. Ce servlet reçoit les requêtes du client API Remote, les distribue au backend approprié, puis renvoie le résultat de l'appel de service au client. Pour installer le servlet API Remote, ajoutez les éléments suivants à votre fichier web.xml :

<servlet>
  <display-name>Remote API Servlet</display-name>
  <servlet-name>RemoteApiServlet</servlet-name>
  <servlet-class>com.google.apphosting.utils.remoteapi.RemoteApiServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>RemoteApiServlet</servlet-name>
  <url-pattern>/remote_api</url-pattern>
</servlet-mapping>

Le servlet renvoie une erreur s'il n'y a pas d'utilisateur authentifié ou si l'utilisateur authentifié n'est pas l'administrateur de votre application. Ainsi, il n'est pas nécessaire de configurer davantage d'options de sécurité. Une fois que vous avez déployé votre application avec ces paramètres, toute application dotée du client API Remote peut utiliser ses services. Cela inclut les clients Python qui se servent de l'API Remote pour Python.

Configurer l'API Remote sur un client autonome

Pour configurer le composant client de l'API Remote afin de l'utiliser dans une application Java, ajoutez ${SDK_ROOT}/lib/impl/appengine-api.jar et ${SDK_ROOT}/lib/appengine-remote-api.jar à votre chemin d'accès aux classes. Ensuite, dans votre code, configurez et installez l'API Remote :

import com.google.appengine.tools.remoteapi.RemoteApiInstaller;
import com.google.appengine.tools.remoteapi.RemoteApiOptions;

// ...
RemoteApiOptions options = new RemoteApiOptions()
    .server("[APP_ID].[REGION_ID].r.appspot.com", 443)
    .useApplicationDefaultCredential();

RemoteApiInstaller installer = new RemoteApiInstaller();
installer.install(options);
// ... all API calls executed remotely
installer.uninstall();

Le client de l'API Remote s'appuiera sur les identifiants par défaut de l'application qui utilisent OAuth 2.0.

Pour obtenir un identifiant, exécutez la commande suivante :

gcloud auth application-default login

Vous pouvez également vous connecter facilement à une application App Engine qui s'exécute localement dans le serveur de développement :

RemoteApiOptions options = new RemoteApiOptions()
    .server("localhost", 8888) // server name must equal "localhost"
    .useDevelopmentServerCredential();

Voici une application Java complète qui, lorsqu'elle est exécutée, insère une entité dans le datastore :

public class RemoteApiExample {

  public static void main(String[] args) throws IOException {
    String serverString = args[0];
    RemoteApiOptions options;
    if (serverString.equals("localhost")) {
      options = new RemoteApiOptions().server(serverString,
        8080).useDevelopmentServerCredential();
    } else {
      options = new RemoteApiOptions().server(serverString,
        443).useApplicationDefaultCredential();
    }
    RemoteApiInstaller installer = new RemoteApiInstaller();
    installer.install(options);
    try {
      DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
      System.out.println("Key of new entity is " + ds.put(new Entity("Hello Remote API!")));
    } finally {
      installer.uninstall();
    }
  }
}

Configurer l'API Remote sur un client App Engine

Vous pouvez également vous servir de l'API Remote pour accéder aux services d'une application App Engine à partir d'une autre application App Engine. Vous devez ajouter un fichier ${SDK_ROOT}/lib/appengine-remote-api.jar au répertoire WEB-INF/lib. Dans l'application App Engine cliente, configurez et installez l'API Remote de la même manière que dans le client Java autonome.

Sachez que RemoteApiInstaller n'installe l'API Remote que sur le thread qui effectue l'installation. Évitez donc de partager les instances de cette classe entre les threads.

Utiliser l'API Remote avec Maven

Pour utiliser la fonctionnalité API Remote dans un projet Maven, ajoutez les dépendances suivantes au fichier pom.xml de votre projet :

<dependency>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-remote-api</artifactId>
  <version>1.9.64</version>
</dependency>
<dependency>
  <groupId>com.google.appengine</groupId>
  <artifactId>appengine-api-1.0-sdk</artifactId>
  <version>1.9.64</version>
</dependency>

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