Accede a App Engine con la API remota

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

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

Habilita la API remota

Primero, agrega el controlador remote_api url a app.yaml. Por ejemplo:

- url: /_ah/remote_api
  script: _go_app

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

Luego, importa el paquete remote_api en uno de los paquetes del proyecto; para ello, agrega la siguiente línea a cualquiera de los archivos de origen de .go:

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

Durante la inicialización del programa, el paquete remote_api registra un controlador para la ruta de acceso /_ah/remote_api. El guion bajo en la declaración de importación significa “importa este paquete, pero no lo usaremos directamente”. Sin el guion bajo, recibirás el mensaje de error “importado, pero no en uso” durante la compilación.

Finalmente, implementa la actualización en App Engine. Por ejemplo:

gcloud app deploy app.yaml

Cómo utilizar la API remota en un cliente local

La API remota puede utilizarse para escribir aplicaciones locales que usan servicios de App Engine y acceden al almacén de datos. Es importante que tengas en cuenta que el uso de la API remota te hará incurrir en el uso de cuotas en la aplicación a la que estás accediendo.

Antes de comenzar, 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 si se crea un contexto con remote_api.NewRemoteContext y se usa ese contexto, en lugar del contexto regular 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 recuperar los siguientes paquetes:

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

Debes proporcionar el nombre de host de tu servidor y un http.Client en la llamada a NewRemoteContext. El http.Client que se proporciona es responsable de pasar la información de autenticación requerida en cada solicitud.

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

Limitaciones y prácticas recomendadas

En el módulo remote_api se toman muchos recaudos para garantizar que, dentro de lo posible, este se comporte exactamente igual que el App Engine Datastore nativo. En algunos casos, eso implica realizar acciones menos eficientes que en otra situación. Cuando se utiliza remote_api, hay que tener en cuenta lo siguiente:

Toda solicitud al almacén de datos necesita un recorrido de ida y vuelta

Debido a que accedes al almacén de datos a través de HTTP, hay un poco más de sobrecarga y latencia que cuando accedes de forma local. Para acelerar el proceso y disminuir la carga, intenta limitar la cantidad de recorridos de ida y vuelta agrupando funciones get y put, y recuperando lotes de entidades a partir de consultas. Este es un buen consejo para remote_api y para el almacén de datos en general, porque cada operación que involucra un lote se considera solo una operación de Datastore.

Las solicitudes a remote_api consumen cuota

Como remote_api funciona a través de HTTP, toda llamada que realizas al almacén de datos consume cuota de solicitudes HTTP, bytes de entrada y de salida, y la cuota habitual del almacén de datos. Tenlo presente si usas remote_api para llevar a cabo actualizaciones en forma masiva.

Se aplican límites de 1 MB a la API

Al igual que cuando se ejecuta de manera nativa, se aplica el límite de 1 MB para las solicitudes y respuestas de la API. Si tus entidades son de gran tamaño, puede que debas limitar el número de operaciones fetch o put simultáneas para mantenerte por debajo de este límite. Lamentablemente, esta recomendación entra en conflicto con la referida a minimizar los recorridos de ida y vuelta; por eso, el mejor consejo es usar lotes del mayor tamaño posible sin sobrepasar las limitaciones de tamaño de las solicitudes o respuestas. De todas formas, es poco probable que esto represente un problema para la mayoría de las entidades.

Evita la iteración en las consultas

Cuando se realizan iteraciones en las consultas, el SDK recupera entidades desde el almacén de datos en lotes de 20, y recupera un lote nuevo cada vez que se agotan las existentes. Como remote_api debe recuperar cada lote mediante una solicitud independiente, no puede hacerlo con gran eficiencia. En cambio, remote_api ejecuta una consulta completamente nueva por cada lote, y usa la funcionalidad de offset para acceder a más resultados.

Si sabes cuántas entidades necesitas, puedes recuperarlas mediante una única solicitud pidiendo esa cantidad.

Si no sabes cuántas entidades querrás, puedes usar cursores para iterar en conjuntos de resultados grandes de forma eficiente. Esto también te permite evitar el límite de 1,000 entidades impuesto sobre las consultas normales del almacén de datos.

Las transacciones son menos eficientes

Para implementar transacciones a través de remote_api, esta acumula información sobre las entidades recuperadas dentro de una transacción, junto con copias de entidades que se ingresaron o borraron dentro de la transacción. Cuando se confirma la transacción, se envía toda esa información al servidor de App Engine, donde se vuelven a recuperar todas las entidades que se utilizaron en la transacción, se verifica que no se hayan modificado y, después, se ingresan y borran todos los cambios que realizó la transacción y se la confirma. Si hay algún conflicto, el servidor revierte la transacción y notifica al cliente, que luego tiene que ejecutar todo el proceso otra vez.

Este método funciona y duplica de manera exacta la funcionalidad provista por las transacciones en el almacén de datos local, pero es bastante ineficiente. Usa transacciones cuando sean necesarias, pero intenta limitar su cantidad y complejidad para lograr una mayor eficiencia.