2011-09-17 12 views
10

Dentro de una tarea, estoy iterando sobre una colección de elementos con una consulta. Después de que se extrae cada entidad de la consulta, también estoy realizando una solicitud de URL. Después de la iteración en un gran número de estos artículos, estoy viendo el siguiente error:Consultas caducadas y appengine

BadRequestError: The requested query has expired. Please restart it with the last cursor to read more results. 

¿Cuál es el contrato de arrendamiento de una consulta una vez que lo crea?

Respuesta

7

Este problema podría arrojar alguna luz sobre su problema: https://code.google.com/p/googleappengine/issues/detail?id=4432

Even though offline requests can currently live up to 10 minutes (and background instances can live forever) datastore queries can still only live for 30 seconds. We plan to improve this, but since a 'consistent' view of the data is only preserved for a limit period of time, there is an upper bound to how long a query can last (which is < 10 minutes).

...

Instead of running a single long query, consider fetching batches from the query using query cursors.

1

Escribí un simple ayudante para hacer esto: lo llamas con el tamaño_batch, la clase de objeto para la consulta y la devolución de llamada que maneja los elementos en la consulta.

(Nota, estoy usando djangoappengine y formato de la consulta, por lo tanto Django - pero se puede modificar para que se ajuste.)

def loop_over_objects_in_batches(batch_size, object_class, callback): 
    logging.info("Calling batched loop with batch_size: %d, object_class: %s, callback: %s" % (batch_size, object_class, callback)) 

    num_els = object_class.objects.all().count() 
    num_loops = num_els/batch_size 
    remainder = num_els - num_loops * batch_size 
    offset = 0 
    while offset < num_loops * batch_size: 
     logging.info("Processing batch (%d:%d)" % (offset, offset+batch_size)) 
     query = object_class.objects.all()[offset:offset + batch_size] 
     for q in query: 
      callback(q) 

     offset = offset + batch_size 

    if remainder: 
     logging.info("Processing remainder batch (%d:-)" % offset) 
     query = object_class.objects.all()[offset:] 
     for q in query: 
      callback(q) 
+0

No había necesidad de contar() y explícitamente trabajar a cabo el resto - el [: ] slice devolverá una consulta de resto y podría detectar eso en el ciclo y partir cuando así sea. Lo escribí explícitamente así para aclarar lo que estaba haciendo. –