Accesso ad App Engine con l'API Remote

Google Cloud CLI include un pacchetto remote_api che ti consente di accedere in modo trasparente ai servizi App Engine da qualsiasi applicazione Go. Ad esempio, puoi utilizzare l'API remota per accedere a Datastore da un'app in esecuzione sulla tua macchina locale o da un'altra delle tue app App Engine.

Per visualizzare i contenuti del pacchetto remote_api, consulta il riferimento al pacchetto remote_api.

Abilitazione dell'API Remote

Per prima cosa, aggiungi il gestore remote_api url al tuo app.yaml. Ad esempio:

- url: /_ah/remote_api
  script: _go_app

In questo modo, l'URL /_ah/remote_api viene mappato alla tua app Go. L'accesso a questo URL è limitato agli amministratori dell'applicazione dal gestore dell'API remota.

Quindi, importa il pacchetto remote_api in uno dei pacchetti del progetto aggiungendo la seguente riga a uno dei file di origine .go:

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

Durante l'inizializzazione del programma, il pacchetto remote_api registra un gestore per il percorso /_ah/remote_api. Il carattere di sottolineatura nella dichiarazione di importazione significa "importa questo pacchetto, ma non lo utilizzeremo direttamente". Senza il trattino basso, riceveresti un messaggio di errore "importato ma non utilizzato" durante la compilazione.

Infine, esegui il deployment dell'aggiornamento in App Engine. Ad esempio:

gcloud app deploy app.yaml

Utilizzo dell'API Remote in un client locale

L'API remota può essere utilizzata per scrivere applicazioni locali che utilizzano i servizi App Engine e accedono al datastore. È importante notare che l'utilizzo dell'API remota comporta l'utilizzo della quota nell'applicazione a cui accedi.

Prima di iniziare, assicurati che l'API Remote sia abilitata nella tua applicazione App Engine. L'applicazione locale può utilizzare l'API Remote creando un contesto con remote_api.NewRemoteContext e utilizzandolo al posto del normale contesto App Engine in tutte le chiamate 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))
}

Per eseguire questo codice, devi recuperare questi pacchetti:

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

Devi fornire il nome host del tuo server e un http.Client nella chiamata a NewRemoteContext. Il http.Client fornito è responsabile del passaggio delle informazioni di autenticazione richieste in ogni richiesta.

Nell'esempio precedente, DefaultClient dal pacchetto golang.org/x/oauth2/google fornisce le credenziali OAuth 2 tramite le credenziali predefinite dell'applicazione.

Limitazioni e best practice

Il modulo remote_api fa di tutto per assicurarsi che, per quanto possibile, si comporti esattamente come il datastore App Engine nativo. In alcuni casi, ciò significa fare cose meno efficienti di quanto potrebbero essere altrimenti. Quando utilizzi remote_api, tieni presente quanto segue:

Ogni richiesta del datastore richiede un round trip

Poiché accedi al datastore tramite HTTP, il sovraccarico e la latenza sono leggermente superiori rispetto all'accesso locale. Per velocizzare le operazioni e ridurre il carico, prova a limitare il numero di round trip eseguito raggruppando le operazioni get e put e recuperando batch di entità dalle query. Questo è un buon consiglio non solo per remote_api, ma per l'utilizzo del datastore in generale, perché un'operazione batch è considerata una singola operazione Datastore.

Richieste di utilizzo della quota di remote_api

Poiché l'API remote_api opera su HTTP, ogni chiamata al datastore che effettui comporta l'utilizzo della quota per le richieste HTTP, i byte in entrata e in uscita, nonché la normale quota del datastore che ti aspetteresti. Tieni presente questo aspetto se utilizzi remote_api per eseguire aggiornamenti collettivi.

Si applicano i limiti API di 1 MB

Come quando viene eseguita in modo nativo, il limite di 1 MB per le richieste e le risposte API è ancora valido. Se le tue entità sono particolarmente grandi, potresti dover limitare il numero di entità recuperate o inserite contemporaneamente per rimanere al di sotto di questo limite. Purtroppo, questo è in conflitto con la riduzione al minimo dei round trip, quindi il consiglio migliore è di utilizzare i batch più grandi possibili senza superare i limiti di dimensioni delle richieste o delle risposte. Per la maggior parte delle entità, tuttavia, è improbabile che si verifichi un problema.

Evita di iterare 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 esaurisce quelli esistenti. Poiché ogni batch deve essere recuperato in una richiesta separata da remote_api, non è possibile farlo in modo efficiente. Al contrario, remote_api esegue una query completamente nuova per ogni batch, utilizzando la funzionalità di offset per approfondire i risultati.

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

Se non sai quante entità ti serviranno, puoi utilizzare i cursori per scorrere in modo efficiente grandi set di risultati. In questo modo puoi anche evitare il limite di 1000 entità imposto alle normali query datastore.

Le transazioni sono meno efficienti

Per implementare le transazioni tramite remote_api, vengono accumulate informazioni sulle entità recuperate all'interno della transazione, insieme a copie delle entità inserite o eliminate all'interno della transazione. Quando la transazione viene eseguita, tutte queste informazioni vengono inviate al server App Engine, dove devono essere recuperate tutte le entità utilizzate nella transazione, verificare che non siano state modificate, quindi inserire ed eliminare tutte le modifiche apportate dalla transazione ed eseguirla. Se si verifica un conflitto, il server esegue il rollback della transazione e invia una notifica al client, che deve ripetere l'intera procedura.

Questo approccio funziona e duplica esattamente la funzionalità fornita dalle transazioni nell'archivio dati locale, ma è piuttosto inefficiente. Utilizza le transazioni dove sono necessarie, ma cerca di limitarne il numero e la complessità per motivi di efficienza.