我编写了一个python脚本来处理CSV文件中的一些数据。该脚本需要3到30分钟才能完成,具体取决于CSV的大小。
现在我想为此添加一个Web界面,以便我可以从任何地方上传CSV数据文件。我写了一个基本的HTTP POST上传页面,并使用了Python的CGI模块 - 但是脚本在一段时间后才会超时。
脚本在开始时输出HTTP标头,并在迭代CSV的每一行之后输出数据位。例如,此打印语句将每30秒左右触发一次。
# at the very top, with the 'import's
print "Content-type: text/html\n\n Processing ... <br />"
# the really long loop.
for currentRecord in csvRecords:
count = count + 1
print "On line " + str(count) + " <br />"
我认为浏览器会收到标题,并等待,因为它会继续接收少量数据。但实际上似乎发生的事情是它根本没有收到任何数据,并且在给定具有大量行的CSV时Error 504
次超时。
也许在某处发生了一些缓存?从日志中,
[Wed Jan 20 16:59:09 2010] [error] [client ::1] Script timed out before returning headers: datacruncher.py, referer: http://localhost/index.htm
[Wed Jan 20 17:04:09 2010] [warn] [client ::1] Timeout waiting for output from CGI script /Library/WebServer/CGI-Executables/datacruncher.py, referer: http://localhost/index.htm
解决此问题的最佳方法是什么,或者,是否不适合在浏览器中运行此类脚本?
修改 这是我自己使用的脚本 - 我通常打算在我的计算机上使用它,但我认为基于Web的界面可以在旅行时派上用场,或者例如从手机上派上用场。此外,实际上没有什么可下载的 - 脚本很可能最终会通过电子邮件发送报告。
答案 0 :(得分:12)
我会将这样的工作分开:
接受POSTed CSV文件的网络应用程序URL。 Web应用程序将CSV内容放入离线队列,例如数据库表。 Web应用程序的响应应该是排队项目的唯一ID(例如,使用自动递增的ID列)。客户必须将此ID存储在第3部分中。
一个独立的服务应用程序,用于轮询队列以进行工作,并进行处理。完成处理后,将结果存储在另一个数据库表中,使用唯一ID作为密钥。
可以获得处理结果的网络应用网址http://server/getresults/uniqueid/
。如果处理完成(即在结果数据库表中找到唯一ID),则返回结果。如果没有完成,响应应该是指示这一点的代码。例如,自定义HTTP标头,HTTP状态响应,响应正文“PENDING”或类似标题。
答案 1 :(得分:5)
我之前遇到过这种情况,我使用过cronjobs。 HTTP脚本只会在队列中写入要执行的作业(DB或目录中的文件),而cronjob会读取它并执行该作业。
答案 2 :(得分:4)
您可能需要执行stdout.flush()
,因为在您编写了一个页面缓冲区的数据之前,脚本还没有真正写入任何内容到网络服务器 - 这在超时之前不会发生
但正如其他人所建议的那样,解决这个问题的正确方法是在单独的线程/进程中进行处理,并向用户显示一个自动刷新的页面,其中显示状态,进度条或其他一些奇特的视觉效果让他们免于厌倦。
答案 3 :(得分:2)
参见Randal Schwartz的Watching long processes through CGI。本文使用Perl,但该技术不依赖于语言。
答案 4 :(得分:2)
非常相似的问题here。我建议在漫长的过程中产生并返回一个基于ajax的进度条给用户。通过这种方式,他们的用户可以享受网络界面的奢华,而且您可以享受无时间的奢侈。
答案 5 :(得分:1)
imho最好的方法是运行一个独立的脚本,在某处发布更新(平面文件,数据库等等)。我不知道如何从python派生一个独立的进程,所以我不能给出任何代码示例。
要在WebSite上显示进度,请向读取这些状态更新的页面实施ajax请求,例如显示一个很好的进度条。
添加类似setTimeout(“refreshProgressBar [...])或元刷新的内容以进行自动刷新。