Como acessar o App Engine com a API Remote

A Google Cloud CLI inclui um pacote remote_api que permite acessar de maneira transparente os serviços do App Engine em qualquer aplicativo Go. Por exemplo, é possível usar a API Remote para acessar o Datastore a partir de um aplicativo em execução na máquina local ou de outro aplicativo do App Engine.

Para ver o conteúdo do pacote remote_api, consulte a referência do pacote remote_api.

Como ativar a API Remote

Primeiro, adicione o gerenciador remote_api url ao seu app.yaml. Por exemplo:

- url: /_ah/remote_api
  script: _go_app

Isso mapeia o URL /_ah/remote_api para o aplicativo Go. O gerenciador da API Remote restringe o acesso a esse URL a administradores do aplicativo.

Em seguida, importe o pacote remote_api em um dos pacotes do projeto adicionando a seguinte linha a qualquer um dos arquivos de origem .go:

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

Durante a inicialização do programa, o pacote remote_api registra um gerenciador para o caminho /_ah/remote_api. O sublinhado na declaração de importação significa "importar este pacote, mas não será usado diretamente". Se não houver o sublinhado, você receberá uma mensagem de erro "importado, mas não usado", na compilação.

Finalmente, você implanta a atualização no App Engine. Por exemplo:

gcloud app deploy app.yaml

Como usar a API Remote em um cliente local

A API Remote pode ser usada para escrever aplicativos locais que usam serviços do App Engine e acessam o armazenamento de dados. É importante observar que o uso da API Remote implica o uso de cota no aplicativo que está sendo acessado.

Antes de começar, verifique se a API Remote está habilitada no aplicativo do App Engine. O aplicativo local pode usar a API Remote criando um contexto com remote_api.NewRemoteContext e usando-o no lugar do contexto regular do App Engine em todas as chamadas de 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))
}

Para executar este código, você precisa buscar os seguintes pacotes:

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

É necessário fornecer o nome do host do servidor e um http.Client na chamada para NewRemoteContext. O http.Client fornecido é responsável por transmitir as informações de autenticação obrigatórias em cada solicitação.

Na amostra acima, o DefaultClient do pacote golang.org/x/oauth2/google fornece credenciais do OAuth 2 por meio do Application Default Credentials.

Limitações e práticas recomendadas

O módulo remote_api empenha um grande esforço para garantir que, até onde for possível, ele se comporte exatamente como o armazenamento de dados nativo do App Engine. Em alguns casos, isso significa executar operações de forma menos eficiente, comparado a outra situação. Ao usar o remote_api, lembre-se:

Cada solicitação do armazenamento de dados requer um percurso completo

Como você está acessando o armazenamento de dados por HTTP, há um pouco mais de sobrecarga e latência do que quando você o acessa localmente. Para agilizar as operações e diminuir a carga, limite o número de percursos de ida e volta por meio de operações em lote de "gets" e "puts" e pela busca de lotes de entidades nas consultas. Isso é recomendável não só para o módulo remote_api, mas para o armazenamento de dados em geral, porque uma operação em lote é considerada apenas como uma única operação do Datastore.

Solicitações para uso da cota do remote_api

Como o remote_api opera com HTTP, cada chamada de armazenamento de dados que você faz utiliza cotas para solicitações HTTP, bytes de entrada e saída, além da cota de armazenamento de dados comum esperada. Lembre-se disso se você estiver usando o remote_api para fazer atualizações em massa.

O limite de 1 MB da API se aplica

Assim como ocorre na execução nativa, o limite de 1 MB para solicitações e respostas da API ainda é aplicável. No caso de entidades grandes, é preciso limitar o número de buscas ou inserções por vez para permanecer abaixo desse limite. Infelizmente, isso causa um conflito com os percursos de ida e volta minimizadores. Por isso, a melhor dica é usar os maiores lotes possíveis sem passar pelas limitações de tamanho de solicitação ou resposta. No entanto, isso provavelmente não será problema para a maioria das entidades.

Evite a iteração de consultas

Ao fazer iterações de consultas, o SDK busca entidades do armazenamento de dados em lotes de 20, buscando um novo lote depois de usar os atuais. Como o remote_api precisar buscar cada lote em uma solicitação separada, ele não consegue fazer isso com tanta eficácia. Em vez disso, ele executa uma consulta totalmente nova para cada lote, usando a funcionalidade de deslocamento para se aprofundar ainda mais nos resultados.

Se você souber de quantas entidades precisa, faça a busca inteira em uma solicitação. Isso pode ser feito com a solicitação do número de que você precisa:

Se não souber de quantas entidades precisa, use os cursores para iterar de forma eficiente em grandes conjuntos de resultados. Isso também evita o limite de 1.000 entidades imposto nas consultas normais ao armazenamento de dados:

As transações são menos eficientes

Para implementar as transações por meio do remote_api, as informações são acumuladas em entidades buscadas na transação, além de cópias das entidades que foram inseridas ou excluídas na transação. Quando executada, a transação envia todas essas informações para o servidor do App Engine, em que é necessário buscar novamente todas as entidades usadas na transação, verificar se não foram modificadas e, em seguida, inserir e excluir todas as alterações feitas pela transação e executá-la. Se houver um conflito, o servidor reverterá a transação e notificará o sistema do cliente, que deverá repetir o processo.

Essa abordagem funciona e duplica exatamente o recurso fornecido pelas transações no armazenamento de dados local, mas é ineficiente. Para não ter dúvidas, use as transações onde forem necessárias, mas tente limitar o número e a complexidade das que forem executadas visando a eficiência.