Accede a App Engine con la API remota

ID de región

REGION_ID es un código abreviado que Google asigna en función de la región que eliges cuando creas la app. El código no corresponde a un país ni a una provincia, aunque algunos ID de región puedan parecer similares a los códigos de país y provincia que se suelen usar. En el caso de las apps creadas después de febrero de 2020, REGION_ID.r se incluye en las URL de App Engine. En el caso de las apps existentes creadas antes de esta fecha, el ID de región es opcional en la URL.

Obtén más información acerca de los ID de región.

La biblioteca de la API remota permite a cualquier cliente de Python acceder a los servicios disponibles para las aplicaciones de App Engine.

Por ejemplo, si la aplicación de App Engine usa Datastore o Google Cloud Storage, un cliente de Python podría acceder a esos recursos de almacenamiento mediante la API remota.

Con la API remota puedes acceder al almacén de datos de tu aplicación desde una aplicación que se ejecuta en tu máquina local o desde una shell interactiva y local de la API remota. La API remota interactúa con los servicios verdaderos, por lo tanto, usa recursos de las cuotas y de facturación.

Habilita el acceso a la API remota en la app

La forma más fácil de habilitar la API remota para la aplicación es mediante la directiva builtins en el archivo app.yaml de la app, que especifica la URL predeterminada /_ah/remote_api/. Sin embargo, puedes usar la directiva url en ese mismo archivo para especificar otra URL.

integrado

La directiva builtins en el archivo app.yaml hace que la API remota esté disponible en la URL predeterminada /_ah/remote_api:

runtime: python27
api_version: 1
threadsafe: true

builtins:
- remote_api: on

URL

El uso de la directiva url en app.yaml te permite especificar una URL diferente para usar con la API remota:

- url: /some-URL/*
  script: google.appengine.ext.remote_api.handler.application

Asegúrate de implementar tu aplicación en App Engine después de realizar este cambio.

Cómo usar la shell de la API remota

El SDK de Python incluye una shell de la API remota que te permite invocar comandos de Python en los servicios de App Engine que usa tu aplicación. No es necesario suministrar ninguna autenticación adicional, ya que esta usa de las mismas credenciales que usaste para subir la aplicación a App Engine forma automática.

Sigue estos pasos para iniciar la shell de la API remota:

  1. Invoca el este comando desde una ventana de terminal en tu máquina local:

    SDK-INSTALL-DIRECTORY/remote_api_shell.py -s YOUR-PROJECT-ID. REGION_ID.r.appspot.com

    Reemplaza [SDK-INSTALL-DIRECTORY] por la ruta de acceso al SDK de App Engine para Python y [YOUR-PROJECT-ID] con el ID del proyecto.

  2. En la shell interactiva que se muestra, invoca a los comandos de Python que quieras ejecutar. Por ejemplo, si la aplicación usa Datastore, puedes invocar la siguiente consulta de ndb para recuperar 10 registros:

     >>> from google.appengine.ext import ndb
     >>>
     >>> # Fetch 10 keys from the datastore
     >>> ndb.Query().fetch(10, keys_only=True)
    

Cómo usar la API remota en un cliente local

También puedes usar la API remota en aplicaciones locales a fin de acceder a los servicios que usa tu aplicación que se ejecuta en App Engine.

Sigue estos pasos para usar la API remota en una aplicación local:

  1. Habilita la API remota.

  2. Exporta el entorno variable PYTHONPATH para tu directorio de Python, por ejemplo:

     export PYTHONPATH=/usr/somedir/v3/bin/python2.7
    

    Reemplaza esa ruta de acceso con los valores reales para tu ubicación de Python.

  3. Agrega el SDK de tu App Engine para la ubicación de Python a PYTHONPATH:

     export GAE_SDK_ROOT="/usr/local/home/mydir/google_appengine"
     export PYTHONPATH=${GAE_SDK_ROOT}:${PYTHONPATH}
    

    Reemplaza la ruta de acceso del SDK que se muestra arriba con tu ruta de acceso real al SDK de App Engine.

  4. En el código de cliente, importa dev_appserver y llama a dev_appserver.fix_sys_path() para asegurarte de que todos los módulos del SDK de App Engine se importen correctamente:

    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
  5. Agrega el siguiente código remote_api_stub a tu aplicación y asegúrate de pasarlo al ID del proyecto en el código:

    remote_api_stub.ConfigureRemoteApiForOAuth(
        '{}.appspot.com'.format(project_id),
        '/_ah/remote_api')

    Si no usas la URL predeterminada /_ah/remote_api para la API remota, deberás cambiar el código anterior a fin de reflejar la URL que estás usando. Para ver la definición y la documentación de remote_api_stub.ConfigureRemoteApiForOAuth, consulta el archivo del SDK [SDK-INSTALL-DIRECTORY]/google/appengine/ext/remote_api/remote_api_stub.py.

  6. Agrega cualquier importación de App Engine necesaria y el código de Python para acceder a los servicios de App Engine deseados. El siguiente código de muestra accede al almacén de datos del proyecto:

    
    import argparse
    
    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
    except ImportError:
        print('Please make sure the App Engine SDK is in your PYTHONPATH.')
        raise
    
    from google.appengine.ext import ndb
    from google.appengine.ext.remote_api import remote_api_stub
    
    def main(project_id):
        remote_api_stub.ConfigureRemoteApiForOAuth(
            '{}.appspot.com'.format(project_id),
            '/_ah/remote_api')
    
        # List the first 10 keys in the datastore.
        keys = ndb.Query().fetch(10, keys_only=True)
    
        for key in keys:
            print(key)
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(
            description=__doc__,
            formatter_class=argparse.RawDescriptionHelpFormatter)
        parser.add_argument('project_id', help='Your Project ID.')
    
        args = parser.parse_args()
    
        main(args.project_id)
  7. Una vez que tu aplicación se implementa en App Engine, inicia el cliente de la API remota:

     python your-client.py YOUR-PROJECT-ID
    

    Reemplaza your-client.py por el módulo de cliente y YOUR-PROJECT-ID por el ID del proyecto. Se supone que el cliente acepta el ID del proyecto como la entrada de la línea de comandos y sigue el ejemplo de código client.py.

Limitaciones y recomendaciones

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 el almacén de datos en general porque a una operación de lote se la considera como una sola operación de Datastore. Por ejemplo, en lugar de realizar esto:

for key in keys:
  rec = key.get()
  rec.foo = bar
  rec.put()

puedes hacer esto:

records = ndb.get_multi(keys)
for rec in records:
  rec.foo = bar
  ndb.put_multi(records)

Ambos ejemplos tienen el mismo efecto, pero el último necesita solo dos idas y vueltas en total, mientras que el primero necesita dos idas y vueltas para cada entidad.

Solicitudes para cuotas de uso de remote_api

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.

Cómo evitar la iteración sobre las consultas

El siguiente es un patrón común con acceso al almacén de datos:

q = MyModel.query()
for entity in q:
  # Do something with entity

Cuando realizas esto, el SDK recupera entidades desde el almacén de datos en lotes de 20. Así, se recupera un lote nuevo cada vez que se termina de consumir el anterior. Debido a que remote_api tiene que recuperar cada lote en una solicitud por separado, no es capaz de hacerlo de manera tan eficiente. En cambio, remote_api ejecuta una consulta nueva por completo por cada lote por medio de la función de compensación para interiorizarte más en los resultados.

Si sabes cuántas entidades necesitas, puedes ejecutar toda la recuperación en una solicitud si pides el número que necesitas:

entities = MyModel.query().fetch(100)
for entity in entities:
  # Do something with entity

Si no sabes cuántas entidades querrás, puedes usar cursores para iterar sobre 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.