Problem
From a Quixote handler, you want to start some lengthy computational task, but don't want to make the user's browser wait while the task is performed.
Solution
Note: this solution is written for Quixote 1.x. The basic idea should still work for Quixote 2, depending on the server technology used.
XXX write this
# This doesn't work if you use cgi.
import datetime, threading, time
_q_exports = ['job']
def _q_index[html](request):
header(request, 'long')
'<a href="job">Start job</a>'
footer(request)
def header[html](request, header, meta=''):
'''<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
%s
<title>%s</title>
</head>
<body>
''' % (meta, header)
def footer[html](request):
'\n </body>\n</html>'
class Thread:
def __init__(self):
self.thread = None
self.status = []
def add_status(self, s):
self.status.append((datetime.datetime.now(), s))
thread = None
semaphore = threading.Semaphore()
def do_job():
thread.add_status('Beginning job.')
thread.add_status('Feeling tired, sleeping 20 seconds.')
time.sleep(20)
thread.add_status('Waking up.')
thread.add_status('Tired again, sleeping 20.')
time.sleep(20)
thread.add_status('Waking up.')
thread.add_status("Now I'm done.")
def start_job():
global thread
semaphore.acquire()
try:
if not thread:
# Start the thread
thread = Thread()
thread.thread = threading.Thread(target=do_job)
thread.thread.start()
finally:
semaphore.release()
def get_status():
status = []
running = False
semaphore.acquire()
try:
if thread:
status = thread.status[:]
if thread.thread and thread.thread.isAlive():
running = True
finally:
semaphore.release()
return running, status
def job[html](request):
start_job()
running, status = get_status()
if running:
#request.response.set_header('Refresh', '5; URL=.')
header(request, 'Job', '<meta http-equiv="Refresh" content="5; URL=%s">' % \
request.get_url())
'<h1>Job status</h3>\n'
else:
header(request, 'Job')
'<h3>Last job log</h3>\n'
for date, msg in status:
'%s %s<br />\n' % (date.isoformat(), msg)
footer(request)