Tengo que resolver un problema similar ahora. No será un sitio público, sino un servidor interno con poco tráfico.
limitaciones técnicas:
- todos los datos de entrada al proceso de larga duración pueden ser suministrados en su inicio
- proceso de larga duración no requiere interacción del usuario (excepto en la entrada inicial para comenzar un proceso)
- el tiempo del cálculo es suficientemente largo para que los resultados no puedan ser notificados al cliente en una respuesta HTTP inmediata
- se requiere algún tipo de comentario (tipo de barra de progreso) del proceso de larga ejecución.
Por lo tanto, necesitamos al menos dos "vistas" web: una para iniciar el proceso de larga ejecución, y la otra, para controlar su estado/recopilar los resultados.
También necesita algún tipo de comunicación entre procesos: enviar datos de usuario desde el iniciador (el servidor web a petición HTTP) a la largo proceso en ejecución, y luego enviar sus resultados a la receptor (de nuevo Web servidor, impulsado por solicitudes http). El primero es fácil, el último es menos obvio. A diferencia de la programación Unix normal, el receptor no se conoce inicialmente. El receptor puede ser un proceso diferente al del iniciador, y puede comenzar cuando el trabajo de larga ejecución aún está en progreso o ya ha finalizado. Entonces, las tuberías no funcionan y necesitamos una cierta permeabilidad de los resultados del largo proceso.
veo dos soluciones posibles:
- lanzamientos de despacho de los largos procesos que se ejecutan en el gestor de trabajos de larga ejecución (esto es probablemente lo que el django-cola de servicio antes mencionado es);
- guardar los resultados en forma permanente, ya sea en un archivo o en el PP.
Preferí usar archivos temporales y recordar su ubicación en los datos de la sesión. No creo que pueda hacerse más simple.
un script de trabajo (este es el proceso de larga duración), myjob.py
:
import sys
from time import sleep
i = 0
while i < 1000:
print 'myjob:', i
i=i+1
sleep(0.1)
sys.stdout.flush()
Django urls.py
mapeo:
urlpatterns = patterns('',
(r'^startjob/$', 'mysite.myapp.views.startjob'),
(r'^showjob/$', 'mysite.myapp.views.showjob'),
(r'^rmjob/$', 'mysite.myapp.views.rmjob'),
)
las vistas de Django:
from tempfile import mkstemp
from os import fdopen,unlink,kill
from subprocess import Popen
import signal
def startjob(request):
"""Start a new long running process unless already started."""
if not request.session.has_key('job'):
# create a temporary file to save the resuls
outfd,outname=mkstemp()
request.session['jobfile']=outname
outfile=fdopen(outfd,'a+')
proc=Popen("python myjob.py",shell=True,stdout=outfile)
# remember pid to terminate the job later
request.session['job']=proc.pid
return HttpResponse('A <a href="/showjob/">new job</a> has started.')
def showjob(request):
"""Show the last result of the running job."""
if not request.session.has_key('job'):
return HttpResponse('Not running a job.'+\
'<a href="/startjob/">Start a new one?</a>')
else:
filename=request.session['jobfile']
results=open(filename)
lines=results.readlines()
try:
return HttpResponse(lines[-1]+\
'<p><a href="/rmjob/">Terminate?</a>')
except:
return HttpResponse('No results yet.'+\
'<p><a href="/rmjob/">Terminate?</a>')
return response
def rmjob(request):
"""Terminate the runining job."""
if request.session.has_key('job'):
job=request.session['job']
filename=request.session['jobfile']
try:
kill(job,signal.SIGKILL) # unix only
unlink(filename)
except OSError, e:
pass # probably the job has finished already
del request.session['job']
del request.session['jobfile']
return HttpResponseRedirect('/startjob/') # start a new one
Sírvanse proporcionar el código que están haciendo para engendrar el procesamiento de fondo. Hay muchas formas de hacerlo, ¿cuál estás usando? –