Acceder a App Engine con la API Remote

La CLI de Google Cloud incluye un paquete remote_api que te permite acceder de forma transparente a los servicios de App Engine desde cualquier aplicación de Go. Por ejemplo, puedes usar la API remota para acceder a Datastore desde una aplicación que se ejecute en tu máquina local o desde otra de tus aplicaciones de App Engine.

Para ver el contenido del paquete remote_api, consulta la referencia del paquete remote_api.

Habilitar la API Remote

Primero, añade el controlador remote_api url a tu app.yaml. Por ejemplo:

- url: /_ah/remote_api
  script: _go_app

De esta forma, se asigna la URL /_ah/remote_api a tu aplicación Go. El acceso a esta URL está restringido a los administradores de la aplicación mediante el controlador de la API remota.

A continuación, importa el paquete remote_api en uno de los paquetes de tu proyecto añadiendo la siguiente línea a cualquiera de tus archivos de origen .go:

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

Durante la inicialización del programa, el paquete remote_api registra un controlador para la ruta /_ah/remote_api. El guion bajo de la declaración de importación significa "importa este paquete, pero no lo usaremos directamente". Sin el guion bajo, recibirías un mensaje de error "importado, pero no usado" al compilar.

Por último, despliega la actualización en App Engine. Por ejemplo:

gcloud app deploy app.yaml

Usar la API remota en un cliente local

La API remota se puede usar para escribir aplicaciones locales que usen los servicios de App Engine y accedan al almacén de datos. Es importante tener en cuenta que, al usar la API Remote, se consumirá cuota en la aplicación a la que accedas.

Antes de empezar, asegúrate de que la API remota esté habilitada en tu aplicación de App Engine. La aplicación local puede usar la API remota creando un contexto con remote_api.NewRemoteContext y usándolo en lugar del contexto normal de App Engine en todas las llamadas a la 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 ejecutar este código, debes obtener estos paquetes:

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

Debe proporcionar el nombre de host de su servidor y un http.Client en la llamada a NewRemoteContext. El http.Client proporcionado es responsable de transmitir la información de autenticación necesaria en cada solicitud.

En el ejemplo anterior, el DefaultClient del paquete golang.org/x/oauth2/google proporciona credenciales de OAuth 2 a través de las credenciales predeterminadas de la aplicación.

Limitaciones y prácticas recomendadas

El módulo remote_api hace todo lo posible para que se comporte exactamente igual que el almacén de datos nativo de App Engine. En algunos casos, esto implica hacer cosas que son menos eficientes de lo que podrían ser. Cuando uses remote_api, ten en cuenta lo siguiente:

Todas las solicitudes del almacén de datos requieren un recorrido de ida y vuelta

Como accedes al almacén de datos a través de HTTP, hay un poco más de sobrecarga y latencia que cuando accedes a él de forma local. Para agilizar las cosas y reducir la carga, intenta limitar el número de viajes de ida y vuelta que haces agrupando las operaciones de obtención e inserción, y obteniendo lotes de entidades de las consultas. Este consejo no solo es útil para remote_api, sino también para usar el almacén de datos en general, ya que una operación por lotes solo se considera una operación de almacén de datos.

Solicitudes de la cuota de uso del módulo remote_api

Como remote_api funciona a través de HTTP, cada llamada a Datastore que hagas incurrirá en el uso de cuota para las solicitudes HTTP, los bytes entrantes y salientes, así como la cuota de Datastore habitual. Tenlo en cuenta si usas remote_api para hacer actualizaciones en bloque.

Aplicación de un límite de 1 MB para el API

Al igual que cuando se ejecuta de forma nativa, se sigue aplicando el límite de 1 MB en las solicitudes y respuestas de la API. Si tus entidades son especialmente grandes, puede que tengas que limitar el número que obtienes o insertas a la vez para no superar este límite. Por desgracia, esto entra en conflicto con la minimización de los viajes de ida y vuelta, por lo que lo más recomendable es usar los lotes más grandes posibles sin superar los límites de tamaño de las solicitudes o las respuestas. Sin embargo, esto no supondría ningún problema para la mayoría de las entidades.

Evitación de la iteración de las consultas

Cuando iteras sobre las consultas, el SDK obtiene entidades del almacén de datos en lotes de 20 y obtiene un nuevo lote cada vez que se agotan los existentes. Como cada lote se tiene que obtener en una solicitud independiente mediante remote_api, no se puede hacer de forma tan eficiente. En su lugar, remote_api ejecuta una consulta completamente nueva para cada lote, usando la función de desplazamiento para obtener más resultados.

Si sabes cuántas entidades necesitas, puedes hacer toda la obtención en una solicitud pidiendo el número que necesites.

Si no sabes cuántas entidades vas a querer, puedes usar cursores para iterar de forma eficiente en conjuntos de resultados grandes. También te permite evitar el límite de 1000 entidades impuesto en las consultas normales de Datastore.

Las transacciones son menos eficientes

Para implementar transacciones a través de remote_api, se acumula información sobre las entidades obtenidas en la transacción, junto con copias de las entidades que se insertaron o eliminaron en la transacción. Cuando se confirma la transacción, se envía toda esta información al servidor de App Engine, donde se deben obtener de nuevo todas las entidades que se han usado en la transacción, verificar que no se han modificado, insertar y eliminar todos los cambios que ha realizado la transacción y confirmarla. Si hay un conflicto, el servidor revierte la transacción y notifica al extremo del cliente, que tiene que repetir el proceso desde el principio.

Este enfoque funciona y duplica exactamente la funcionalidad que ofrecen las transacciones en el almacén de datos local, pero es bastante ineficiente. Usa transacciones siempre que sea necesario, pero intenta limitar el número y la complejidad de las transacciones que ejecutes para mejorar la eficiencia.