API Remote per servizi in bundle legacy

L'SDK Java include una libreria denominata API Remote che ti consente di accedere in modo trasparente ai servizi App Engine da qualsiasi applicazione Java. Ad esempio, puoi utilizzare l'API Remote per accedere a un datastore di produzione da un'app in esecuzione sulla tua macchina locale. Puoi anche utilizzare l'API Remote per accedere al datastore di un'app App Engine da un'altra app di App Engine.

Configurazione dell'API Remote sul server

Il componente server dell'API Remote è un servlet Java che fa parte del runtime App Engine per Java. Questo servlet riceve le richieste dal client dell'API Remote, le invia al servizio di backend appropriato, quindi restituisce il risultato della chiamata al client. Per installare il servlet dell'API Remote, aggiungi quanto segue a 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>

Il servlet restituisce un errore se non esiste un utente autenticato o se l'utente autenticato non è un amministratore dell'applicazione, quindi non è necessario configurare alcuna sicurezza aggiuntiva. Dopo aver eseguito il deployment dell'app con queste impostazioni, qualsiasi app su cui è installato il client API Remote può utilizzare i propri servizi. Sono inclusi i client Python che utilizzano l'API Python Remote.

Configurazione dell'API Remote su un client autonomo

Per configurare il componente client dell'API Remote da utilizzare all'interno di un'applicazione Java, aggiungi ${SDK_ROOT}/lib/impl/appengine-api.jar e ${SDK_ROOT}/lib/appengine-remote-api.jar a classpath. Quindi, nel tuo codice, configura e installa 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();

Il client API Remote si baserà sulle Credenziali predefinite dell'applicazione che usano OAuth 2.0.

Per ottenere un'esecuzione delle credenziali:

gcloud auth application-default login

Puoi connetterti con la stessa facilità a un'app App Engine eseguita localmente nel server di sviluppo:

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

Ecco un'applicazione Java completa che, quando viene eseguita, inserisce un'entità nel 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();
    }
  }
}

Configurazione dell'API Remote su un client App Engine

Puoi anche utilizzare l'API Remote per accedere ai servizi di un'applicazione App Engine da un'altra applicazione App Engine. Devi aggiungere ${SDK_ROOT}/lib/appengine-remote-api.jar alla directory WEB-INF/lib e poi, nell'app client App Engine, configurare e installare l'API Remote come hai fatto nel tuo client Java autonomo.

Tieni presente che RemoteApiInstaller installa l'API Remote solo nel thread che esegue l'installazione, quindi presta attenzione a non condividere istanze di questa classe tra i thread.

Utilizzo dell'API Remote con Maven

Per utilizzare la funzionalità dell'API Remote nel progetto Maven, aggiungi le seguenti dipendenze al file pom.xml del progetto:

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

Limitazioni e best practice

Il modulo remote_api fa di tutto per assicurarsi che, per quanto possibile, si comporti esattamente come il datastore nativo di App Engine. In alcuni casi, ciò significa fare cose che sono meno efficienti di quante altre potrebbero esserlo. Ecco alcuni aspetti da tenere presente quando utilizzi remote_api:

Ogni richiesta di datastore richiede un andata e ritorno

Poiché si accede al datastore tramite HTTP, il sovraccarico e la latenza sono leggermente più numerosi rispetto a quando si accede localmente. Per velocizzare le cose e ridurre il carico, prova a limitare il numero di round trip che esegui raggruppando i dati get e put e recuperando batch di entità dalle query. Questo è un buon consiglio non solo per remote_api, ma anche per l'utilizzo del datastore in generale, dato che un'operazione batch viene considerata come una singola operazione Datastore.

Quota di utilizzo delle richieste per remote_api

Poiché Remote_api funziona su HTTP, ogni chiamata al datastore effettuata comporta l'utilizzo di una quota per le richieste HTTP, di byte in entrata e in uscita, oltre alla consueta quota di datastore prevista. Tieni presente questo aspetto se utilizzi remote_api per eseguire aggiornamenti collettivi.

Si applicano limiti API di 1 MB

Come per l'esecuzione nativa, il limite di 1 MB per le richieste e le risposte API continua a essere applicato. Se le entità sono particolarmente grandi, potrebbe essere necessario limitare il numero recuperato o messo alla volta per rimanere al di sotto di questo limite. Purtroppo, ciò è in conflitto con la riduzione al minimo dei round trip, pertanto il consiglio migliore è utilizzare batch di dimensioni maggiori senza superare i limiti di dimensione delle richieste o delle risposte. Per la maggior parte delle entità, tuttavia, questo non è un problema.

Evita di utilizzare iterazioni per le query

Quando esegui l'iterazione delle query, l'SDK recupera le entità dal datastore in batch di 20, recuperando un nuovo batch ogni volta che utilizza quelli esistenti. Poiché ogni batch deve essere recuperato in una richiesta separata da remote_api, non è possibile farlo con la stessa efficienza. Al contrario, remote_api esegue una query completamente nuova per ogni batch, utilizzando la funzionalità di offset per analizzare meglio i risultati.

Se sai di quante entità hai bisogno, puoi eseguire l'intero recupero in un'unica richiesta chiedendo il numero che ti serve.

Se non sai quante entità vuoi, puoi utilizzare i cursors per eseguire l'iterazione in modo efficiente su set di risultati di grandi dimensioni. Ciò consente inoltre di evitare il limite di 1000 entità imposto alle normali query sul datastore.

Le transazioni sono meno efficienti

Al fine di implementare le transazioni tramite remote_api, questo metodo raccoglie informazioni sulle entità recuperate all'interno della transazione, insieme alle copie delle entità inserite o eliminate all'interno della transazione. Quando viene eseguito il commit della transazione, invia tutte queste informazioni al server App Engine, dove deve recuperare nuovamente tutte le entità utilizzate nella transazione, verificare che non siano state modificate, quindi inserire ed eliminare tutte le modifiche apportate ed eseguire il commit. In caso di conflitto, il server esegue il rollback della transazione e notifica la fine del client, che deve ripetere il processo da capo.

Questo approccio funziona e duplica esattamente la funzionalità fornita dalle transazioni sul datastore locale, ma è piuttosto inefficiente. Usa sicuramente le transazioni dove necessario, ma cerca di limitare il numero e la complessità delle transazioni eseguite nell'interesse dell'efficienza.