¿Cómo ejecutar tareas en segundo plano en appengine?Tareas de fondo en appengine
Respuesta
GAE es una herramienta muy útil para crear aplicaciones web escalables. Algunas de las limitaciones señaladas por muchos no son compatibles con tareas en segundo plano, falta de tareas periódicas y límite estricto de cuánto tarda cada solicitud HTTP, si una solicitud excede ese límite de tiempo, la operación finaliza, lo que hace que las tareas que consumen tiempo sean imposibles. .
¿Cómo ejecutar la tarea en segundo plano?
En GAE, el código se ejecuta solo cuando hay una solicitud HTTP. Hay un límite de tiempo estricto (creo que 10 segundos) sobre cuánto tiempo puede tomar el código. Entonces, si no hay solicitudes, el código no se ejecuta. Uno de los trabajos sugeridos fue usar una caja externa para enviar solicitudes continuamente, creando así una tarea de fondo. Pero para esto necesitamos una caja externa y ahora dependemos de un elemento más. La otra alternativa era enviar 302 una respuesta de redireccionamiento para que el cliente reenviara la solicitud, esto también nos hace dependientes del elemento externo que es el cliente. ¿Qué pasa si esa caja externa es GAE en sí? Todos los que han utilizado un lenguaje funcional que no admite la construcción de bucles en el lenguaje conocen la alternativa, es decir, la recursividad es el bucle de sustitución. Entonces, ¿qué pasa si completamos parte de la computación y hacemos un HTTP GET en la misma url con muy poco tiempo de espera, por ejemplo, 1 segundo? Esto crea un bucle (recursión) en el código php que se ejecuta en apache.
<?php $i = 0; if(isset($_REQUEST["i"])){ $i= $_REQUEST["i"]; sleep(1); } $ch = curl_init("http://localhost".$_SERVER["PHP_SELF"]."?i=".($i+1)); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_TIMEOUT, 1); curl_exec($ch); print "hello world\n"; ?>
De alguna manera esto no funciona en GAE. Entonces, ¿qué pasa si hacemos HTTP GET en alguna otra url, digamos url2, que hace HTTP GET en la primera url? Esto parece funcionar en GAE. El código para esto se parece a esto.
class FirstUrl(webapp.RequestHandler): def get(self): self.response.out.write("ok") time.sleep(2) urlfetch.fetch("http://"+self.request.headers["HOST"]+'/url2') class SecondUrl(webapp.RequestHandler): def get(self): self.response.out.write("ok") time.sleep(2) urlfetch.fetch("http://"+self.request.headers["HOST"]+'/url1') application = webapp.WSGIApplication([('/url1', FirstUrl), ('/url2', SecondUrl)]) def main(): run_wsgi_app(application) if __name__ == "__main__": main()
Como nos dimos cuenta de una forma de ejecutar tareas en segundo plano, permite construir abstracciones de tarea periódica (temporizador) y una estructura iterativa que se extiende a través de muchas peticiones HTTP (foreach).
Temporizador
Ahora el temporizador de construcción es sencillo. La idea básica es tener una lista de temporizadores y el intervalo al que se debe llamar cada uno. Una vez que alcanzamos ese intervalo llamamos a la función de devolución de llamada. Usaremos Memcache para mantener la lista de temporizadores. Para saber cuándo llamar a la devolución de llamada, almacenaremos una clave en Memcache con intervalo como tiempo de caducidad. Periódicamente (digamos 5 segundos) verificamos si esa clave está presente, si no está presente, llamamos a la devolución de llamada y nuevamente configuramos esa tecla con el intervalo.
def timer(func, interval): timerlist = memcache.get('timer') if(None == timerlist): timerlist = [] timerlist.append({'func':func, 'interval':interval}) memcache.set('timer-'+func, '1', interval) memcache.set('timer', timerlist) def checktimers(): timerlist = memcache.get('timer') if(None == timerlist): return False for current in timerlist: if(None == memcache.get('timer-'+current['func'])): #reset interval memcache.set('timer-'+current['func'], '1', current['interval']) #invoke callback function try: eval(current['func']+'()') except: pass return True return False
Foreach
Esto es necesario cuando queremos hacer larga la toma de cómputo decir hacer alguna operación en 1000 filas de bases de datos o ir a buscar 1000 URLs etc. idea básica es la lista de las devoluciones de llamada y argumentos en Memcache mantener y cada vez invocar devolución de llamada con el argumento.
def foreach(func, args): looplist = memcache.get('foreach') if(None == looplist): looplist = [] looplist.append({'func':func, 'args':args}) memcache.set('foreach', looplist) def checkloops(): looplist = memcache.get('foreach') if(None == looplist): return False if((len(looplist) > 0) and (len(looplist[0]['args']) > 0)): arg = looplist[0]['args'].pop(0) func = looplist[0]['func'] if(len(looplist[0]['args']) == 0): looplist.pop(0) if((len(looplist) > 0) and (len(looplist[0]['args']) > 0)): memcache.set('foreach', looplist) else: memcache.delete('foreach') try: eval(func+'('+repr(arg)+')') except: pass return True else: return False # instead of # foreach index in range(0, 1000): # someoperaton(index) # we will say # foreach('someoperaton', range(0, 1000))
Ahora construir un programa que obtenga la lista de URL cada hora es sencillo. Aquí está el código.
def getone(url): try: result = urlfetch.fetch(url) if(result.status_code == 200): memcache.set(url, '1', 60*60) #process result.content except : pass def getallurl(): #list of urls to be fetched urllist = ['http://www.google.com/', 'http://www.cnn.com/', 'http://www.yahoo.com', 'http://news.google.com'] fetchlist = [] for url in urllist: if (memcache.get(url) is None): fetchlist.append(url) #this is equivalent to #for url in fetchlist: getone(url) if(len(fetchlist) > 0): foreach('getone', fetchlist) #register the timer callback timer('getallurl', 3*60)
código completo está aquí http://groups.google.com/group/httpmr-discuss/t/1648611a54c01aa He estado corriendo este código en appengine de unos días sin mucho problema.
Advertencia: Hacemos un uso intensivo de urlfetch. El límite en no de urlfetch por día es 160000. Por lo tanto, tenga cuidado de no alcanzar ese límite.
¡increíble! me gusta – fuentesjr
No veo cómo puede funcionar. ¿No superarás la cuota de 10 segundos en la sexta búsqueda recursiva? – Constantin
Corrígeme si estoy equivocado, ¿no hay alguna política de AppEngine sobre la intercomunicación entre aplicaciones alojadas? – zotherstupidguy
La próxima versión de runtime tendrá algún tipo de motor de ejecución periódica a'la cron. Ver this message en el grupo de App Engine.
Entonces, todas las piezas del SDK parecen funcionar, pero mis pruebas indican que esto todavía no se está ejecutando en los servidores de producción: configuré un cron "cada 1 minutos" que se registra cuando se ejecuta y no ha sido llamado todavía
es difícil decir cuándo va a estar disponible, aunque ...
Usted puede utilizar el Task Queue Python API.
utilizar la cola de tareas - http://code.google.com/appengine/docs/java/taskqueue/overview.html
-1; esta es esencialmente la misma respuesta publicada y aceptada hace 2 años, con un enlace a los documentos de Java en lugar de los documentos de Python, cuando el OP estaba usando Python. ¿Seriamente? – geoffspear
Si desea ejecutar fondo tareas periódicas, consulte this question (cron de App Engine)
Si sus tareas no son periódicas, consulte Task Queue Python API o Task Queue Java API
Puede Obtenga más información sobre trabajos cron en Python App Engine here.
Hay una instalación de cron integrada en el motor de aplicaciones.
Por favor, se refieren a: https://developers.google.com/appengine/docs/python/config/cron?hl=en
utilizando los Deferred Python Library es la forma más fácil de hacer tarea en segundo plano en AppEngine usando Python que se construye en la parte superior de la API TaskQueue.
from google.appengine.ext import deferred
def do_something_expensive(a, b, c=None):
logging.info("Doing something expensive!")
# Do your work here
# Somewhere else
deferred.defer(do_something_expensive, "Hello, world!", 42, c=True)
Existen ventajas y desventajas para usar la biblioteca diferida; consulte la sección "Cuándo usar ext.deferred" en el artículo de Nick Johnson: https://cloud.google.com/appengine/articles/deferred?hl=en –
- 1. Programación de tareas en AppEngine dev_appserver.py
- 2. Cancelar tareas de fondo
- 3. Cola de tareas de prueba unitarias en AppEngine
- 4. Aplicación iOS ejecutando tareas en el fondo
- 5. ¿Cómo puedo verificar programáticamente el estado de mi cola de tareas en Google Appengine?
- 6. Ejecutar la función cuando la cola de tareas está vacía en appengine
- 7. MiniProfiler, primeras tareas del fondo EntityFramework y tareas en segundo plano nullreference
- 8. ¿Las tareas se crean como subprocesos de fondo?
- 9. Django 1.3 en appengine
- 10. django en Google Appengine
- 11. rastreador en appengine
- 12. tamaño máximo en BlobProperty (appengine)
- 13. Solicitudes concurrentes en Appengine Python
- 14. ¿Cómo registrar excepciones en appengine?
- 15. Búsqueda de comodines en Appengine en python
- 16. Enviar mensajes de correo electrónico en tareas del trabajo de fondo/programada en asp.net mvc 3
- 17. Límites de registro de AppEngine
- 18. Depurando tareas en segundo plano
- 19. Conexión de gancho en Google Appengine
- 20. análisis de solicitudes formateadas json en appengine
- 21. Filtro de desigualdad en AppEngine Datastore
- 22. instalando simplejson en la appengine de google
- 23. Colocando datos directamente en Blobstore de AppEngine
- 24. Hora de JODA en Java Appengine
- 25. Appengine Blobstore - Video Streaming
- 26. AppEngine compresión gzip
- 27. Consultas caducadas y appengine
- 28. Google appengine datastore alternative?
- 29. Programador de tareas de Windows para ejecutar tareas en segundos
- 30. Lista de verificación para java thread-safe en appengine
Probablemente debería eliminar la etiqueta php, ya que php no funciona en GAE. –