2014-07-16 10 views
5

Ho un programma di Google App Engine che richiede BigQuery per i dati.Come impostare scadenza per BigQuery su Google App Engine

La query richiede solitamente 3 - 4.5 secondi e va bene, ma a volte prende più di cinque secondi e getta questo errore:

DeadlineExceededError: The API call urlfetch.Fetch() took too long to respond and was cancelled.

Questo article mostra le scadenze e le diverse tipologie di errori di scadenza.

C'è un modo per impostare la scadenza di un lavoro BigQuery per essere al di sopra di 5 secondi? Impossibile trovarlo nei documenti dell'API di BigQuery.

risposta

6

query BigQuery sono veloci, ma spesso richiedono più tempo di App Engine UrlFetch predefinito di timeout. L'API BigQuery è asincrona, quindi è necessario suddividere i passaggi in chiamate API che siano inferiori a 5 secondi.

Per questa situazione, vorrei utilizzare il App Engine Task Queue:

  1. Effettuare una chiamata al API BigQuery per inserire il tuo lavoro. Questo restituisce un JobID.

  2. Posizionare un compito sulla coda compito App Engine per verificare lo stato del lavoro di query BigQuery in quel ID.

  3. Se lo Stato BigQuery lavoro non è "DONE", inserire una nuova attività sulla coda per controllare di nuovo.

  4. Se lo stato è "fatto", quindi effettuare una chiamata utilizzando UrlFetch per recuperare i risultati.

+0

Perfetto. Grazie, Michael! – humanbeing

4

Nota Vorrei andare con il suggerimento di Michael poiché quello è il più robusto. Volevo solo sottolineare che è possibile aumentare il timeout dell'URL fino a 60 secondi, il che dovrebbe essere sufficiente per completare la maggior parte delle query.

How to set timeout for urlfetch in Google App Engine?

+0

Grazie Jordan. Vado con Michaels ma è bello sapere che posso farlo anche come soluzione rapida quando si sviluppa. Saluti! – humanbeing

0

non sono riuscito a ottenere il metodo urlfetch.set_default_fetch_deadline() da applicare alle API Big Query, ma era in grado di aumentare il timeout quando autorizza la grande sessione di query come segue:

from apiclient.discovery import build 
from oauth2client.service_account import ServiceAccountCredentials 

credentials = ServiceAccountCredentials.from_json_keyfile_dict(credentials_dict, scopes) 

# Create an authorized session and set the url fetch timeout. 
http_auth = credentials.authorize(Http(timeout=60)) 

# Build the service. 
service = build(service_name, version, http=http_auth) 

# Make the query 
request = service.jobs().query(body=query_body).execute() 

O con un approccio asincrono utilizzando jobs().insert

query_response = service.jobs().insert(body=query_body).execute() 

big_query_job_id = query_response['jobReference']['jobId'] 

# poll the job.get endpoint until the job is complete 
while True: 

    job_status_response = service.jobs()\ 
     .get(jobId=big_query_job_id).execute() 

    if job_status_response['status']['state'] == done: 
     break 

    time.sleep(1) 

results_respone = service.jobs()\ 
    .getQueryResults(**query_params)\ 
    .execute() 

abbiamo finito per andare con un approccio simile a quello che Micha el suggerisce sopra, tuttavia, anche quando si utilizza la chiamata asincrona, il metodo getQueryResults (impaginato con un piccolo parametro maxResults) è scaduto durante il recupero dell'URL, generando l'errore indicato nella domanda.

Quindi, al fine di aumentare il timeout di recupero URL in Big Query/App Engine, impostare il timeout di conseguenza quando si autorizza la sessione.

0

Per inviare richieste HTTP in AppEngine è possibile utilizzare urllib, urllib2, httplib o urlfetch. Tuttavia, indipendentemente dalla libreria scelta, AppEngine eseguirà le richieste HTTP utilizzando App Engine's URL Fetch service.

googleapiclientuses . Sembra che httplib2.Http passi il timeout per urlfetch. Poiché ha un valore predefinito None, urlfetch imposta la scadenza di tale richiesta su 5s, indipendentemente da ciò che hai impostato con urlfetch.set_default_fetch_deadline.

Sotto le coperture httplib2 uses la libreria socket per richieste HTTP.

Per impostare il timeout è possibile effettuare le seguenti operazioni:

import socket 
socket.setdefaulttimeout(30) 

Si dovrebbe anche essere in grado di fare questo, ma non ho provato:

http = httplib2.Http(timeout=30) 

Se non hanno codice esistente al momento della richiesta si può avvolgere la query in questo modo:

import time 
start_query = time.time() 

<your query code> 

end_query = time.time() 
print(end_query - start_query) 
0

questo è un modo per risolvere i timeout BigQuery in AppEngin e per Go. Basta impostare TimeoutMs per le tue query ben al di sotto di 5000. Il timeout predefinito per le query bigquery è 10000ms, che supera la scadenza predefinita di 5 secondi per le richieste in uscita in AppEngine.

Il getcha è che il timeout deve essere impostato sia nella richiesta iniziale: bigquery.service.Jobs.Query(…) sia nel successivo b.service.Jobs.GetQueryResults(…) che si utilizza per eseguire il polling dei risultati della query.

Esempio:

query := &gbigquery.QueryRequest{ 
    DefaultDataset: &gbigquery.DatasetReference{ 
     DatasetId: "mydatasetid", 
     ProjectId: "myprojectid", 
    }, 
    Kind:  "json", 
    Query:  "<insert query here>", 
    TimeoutMs: 3000, // <- important! 
} 

queryResponse := bigquery.service.Jobs.Query("myprojectid", query).Do() 

// determine if queryResponse is a completed job and if not start to poll 

queryResponseResults := bigquery.service.Jobs. 
     GetQueryResults("myprojectid", res.JobRef.JobId). 
     TimeoutMs(DefaultTimeoutMS) // <- important! 

// determine if queryResponseResults is a completed job and if not continue to poll 

La cosa bella di questo è che si mantiene la scadenza richiesta di default per la richiesta complessiva (60 per le richieste normali e 10 minuti per i compiti e cronjobs), evitando fissa la scadenza per le richieste in uscita con un certo valore arbitrario.