Accesso ad App Engine con l'API Remote

ID regione

REGION_ID è un codice abbreviato assegnato da Google in base alla regione selezionata al momento della creazione dell'app. Non corrisponde a un paese o a una provincia, anche se alcuni ID regione possono apparire simili ai codici di paese e provincia di uso comune. Per le app create dopo febbraio 2020, REGION_ID.r è incluso negli URL di App Engine. Per le app esistenti create prima di questa data, l'ID regione è facoltativo nell'URL.

Scopri di più sugli ID regione.

La libreria API Remote consente a qualsiasi client Python di accedere ai servizi disponibili per le applicazioni App Engine.

Ad esempio, se l'applicazione App Engine utilizza Datastore o Google Cloud Storage, un client Python potrebbe accedere a queste risorse di archiviazione utilizzando l'API Remote.

Puoi utilizzare l'API Remote per accedere al datastore della tua applicazione da un'app in esecuzione sulla tua macchina locale o da una shell dell'API Remote interattiva locale. L'API remota interagisce con i servizi reali, pertanto questo accesso utilizza quota e risorse fatturabili.

Attivazione dell'accesso all'API Remote nella tua app

Il modo più semplice per attivare l'API Remote per la tua applicazione è utilizzare l'istruzione builtins nel file app.yaml dell'app, che specifica l'URL predefinito /_ah/remote_api/. Tuttavia, puoi utilizzare l'istruzione url nello stesso file per specificare un altro URL.

integrato

L'istruzione builtins nel file app.yaml rende disponibile l'API Remote all'URL predefinito /_ah/remote_api:

runtime: python27
api_version: 1
threadsafe: true

builtins:
- remote_api: on

URL

L'utilizzo dell'istruzione url in app.yaml consente di specificare un URL diverso da utilizzare con l'API Remote:

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

Assicurati di eseguire il deployment della tua applicazione in App Engine dopo aver apportato questa modifica.

Utilizzo della shell dell'API Remote

L'SDK Python include una shell dell'API Remote che consente di richiamare i comandi Python sui servizi App Engine utilizzati dalla tua applicazione. Non è necessario fornire ulteriori autenticazioni poiché vengono usate automaticamente le stesse credenziali utilizzate per caricare l'app in App Engine.

Per avviare la shell dell'API Remote:

  1. Richiama il seguente comando da una finestra del terminale sulla macchina locale:

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

    Sostituisci [SDK-INSTALL-DIRECTORY] con il percorso dell'SDK di App Engine per Python e [YOUR-PROJECT-ID] con il tuo ID progetto.

  2. Nella shell interattiva visualizzata, richiama i comandi Python che vuoi eseguire. Ad esempio, se l'applicazione utilizza Datastore, puoi richiamare la seguente query ndb per recuperare 10 record:

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

Utilizzo dell'API Remote in un client locale

Puoi utilizzare l'API Remote anche nelle applicazioni locali per accedere ai servizi utilizzati dalla tua app in esecuzione in App Engine.

Per utilizzare l'API Remote in un'applicazione locale:

  1. Attiva l'API remota.

  2. Esporta la variabile di ambiente PYTHONPATH per la directory Python, ad esempio:

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

    Sostituisci il percorso con i valori effettivi della posizione Python.

  3. Aggiungi il tuo SDK App Engine per la località Python a PYTHONPATH:

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

    Sostituisci il percorso dell'SDK mostrato sopra con il percorso effettivo all'SDK App Engine.

  4. Nel codice client, importa dev_appserver e chiama dev_appserver.fix_sys_path() per assicurarti che tutti i moduli SDK di App Engine vengano importati correttamente:

    try:
        import dev_appserver
        dev_appserver.fix_sys_path()
  5. Aggiungi il seguente codice remote_api_stub all'applicazione, assicurandoti di trasmetterlo al tuo ID progetto nel codice:

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

    Se non utilizzi l'URL predefinito /_ah/remote_api per l'API Remote, dovrai modificare il codice riportato sopra in modo che rifletta l'URL che stai utilizzando. Per la definizione e la documentazione per remote_api_stub.ConfigureRemoteApiForOAuth, consulta il file SDK [SDK-INSTALL-DIRECTORY]/google/appengine/ext/remote_api/remote_api_stub.py.

  6. Aggiungi eventuali importazioni App Engine necessarie e codice Python per accedere ai servizi App Engine desiderati. Il seguente codice campione consente di accedere al datastore del progetto:

    
    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. Dopo il deployment dell'applicazione in App Engine, avvia il client API Remote:

     python your-client.py YOUR-PROJECT-ID
    

    Sostituisci your-client.py con il modulo client e YOUR-PROJECT-ID con l'ID progetto. Questo presuppone che il tuo client accetti l'ID progetto come input della riga di comando, seguendo l'esempio di codice client.py.

Limitazioni e best practice

Il modulo remote_api fa di tutto per assicurarsi che, per quanto possibile, si comporti esattamente come il datastore nativo di App Engine. In alcuni casi, ciò significa fare cose che sono meno efficienti di quante altre potrebbero esserlo. Ecco alcuni aspetti da tenere presente quando utilizzi remote_api:

Ogni richiesta di datastore richiede un andata e ritorno

Poiché si accede al datastore tramite HTTP, il sovraccarico e la latenza sono leggermente più numerosi rispetto a quando si accede localmente. Per velocizzare le cose e ridurre il carico, prova a limitare il numero di round trip che esegui raggruppando i dati get e put e recuperando batch di entità dalle query. Questo è un buon consiglio non solo per remote_api, ma anche per l'utilizzo del datastore in generale, dato che un'operazione batch viene considerata come una singola operazione Datastore. Ad esempio, invece di questo:

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

puoi farlo:

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

Entrambi gli esempi hanno lo stesso effetto, ma il secondo richiede solo due round trip in totale, mentre il primo richiede due round trip per ogni entità.

Quota di utilizzo delle richieste per remote_api

Poiché Remote_api funziona su HTTP, ogni chiamata al datastore effettuata comporta l'utilizzo di una quota per le richieste HTTP, di byte in entrata e in uscita, oltre alla consueta quota di datastore prevista. Tieni presente questo aspetto se utilizzi remote_api per eseguire aggiornamenti collettivi.

Si applicano limiti API di 1 MB

Come per l'esecuzione nativa, il limite di 1 MB per le richieste e le risposte API continua a essere applicato. Se le entità sono particolarmente grandi, potrebbe essere necessario limitare il numero recuperato o messo alla volta per rimanere al di sotto di questo limite. Purtroppo, ciò è in conflitto con la riduzione al minimo dei round trip, pertanto il consiglio migliore è utilizzare batch di dimensioni maggiori senza superare i limiti di dimensione delle richieste o delle risposte. Per la maggior parte delle entità, tuttavia, questo non è un problema.

Evita di utilizzare iterazioni per le query

Un modello comune con l'accesso al datastore è il seguente:

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

In questo modo, l'SDK recupera le entità dal datastore in batch di 20, recuperando un nuovo batch ogni volta che utilizza 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 analizzare meglio i risultati.

Se sai di quante entità hai bisogno, puoi eseguire l'intero recupero in un'unica richiesta chiedendo il numero che ti serve:

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

Se non sai quante entità vuoi, puoi utilizzare i cursors per eseguire l'iterazione in modo efficiente su set di risultati di grandi dimensioni. Ciò consente inoltre di evitare il limite di 1000 entità imposto alle normali query sul datastore.

Le transazioni sono meno efficienti

Al fine di implementare le transazioni tramite remote_api, questo metodo raccoglie informazioni sulle entità recuperate all'interno della transazione, insieme alle copie delle entità inserite o eliminate all'interno della transazione. Quando viene eseguito il commit della transazione, invia tutte queste informazioni al server App Engine, dove deve recuperare nuovamente tutte le entità utilizzate nella transazione, verificare che non siano state modificate, quindi inserire ed eliminare tutte le modifiche apportate ed eseguire il commit. In caso di conflitto, il server esegue il rollback della transazione e notifica la fine del client, che deve ripetere il processo da capo.

Questo approccio funziona e duplica esattamente la funzionalità fornita dalle transazioni sul datastore locale, ma è piuttosto inefficiente. Usa sicuramente le transazioni dove necessario, ma cerca di limitare il numero e la complessità delle transazioni eseguite nell'interesse dell'efficienza.