7

我编写了一个 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 />"

我假设浏览器会收到标头,然后等待,因为它会继续接收少量数据。但实际上似乎发生的是它根本没有收到任何数据,并且Error 504在给定包含很多行的 CSV 时会超时。

也许某处发生了一些缓存?从日志中,

[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 的界面可以在旅行时派上用场,或者例如通过电话。此外,实际上没有什么可下载的——脚本很可能会在最后通过电子邮件发送一份报告。

4

6 回答 6

12

我会这样分开工作:

  1. 接受 POST CSV 文件的 Web 应用 URL。Web 应用程序将 CSV 内容放入离线队列,例如数据库表。Web 应用程序的响应应该是排队项目的唯一 ID(例如,使用自动递增的 ID 列)。客户端必须为第 3 部分存储此 ID。

  2. 一个独立的服务应用程序,它轮询工作队列并进行处理。处理完成后,将结果存储在另一个数据库表中,使用唯一 ID 作为键。

  3. 可以获取处理结果的 Web 应用 URL http://server/getresults/uniqueid/,. 如果处理完成(即在结果数据库表中找到唯一ID),则返回结果。如果未完成,则响应应该是表明这一点的代码。例如自定义 HTTP 标头、HTTP 状态响应、响应正文“PENDING”或类似内容。

于 2010-01-20T12:00:21.677 回答
5

我以前遇到过这种情况,我使用了 cronjobs。HTTP 脚本只会在队列中写入要执行的作业(数据库或目录中的文件),而 cronjob 会读取它并执行该作业。

于 2010-01-20T11:52:15.567 回答
4

您可能需要执行 a stdout.flush(),因为在您写入页面缓冲区的数据之前,脚本还没有真正向网络服务器写入任何内容 - 这在超时之前不会发生。

但是,正如其他人所建议的那样,解决此问题的正确方法是在单独的线程/进程中进行处理,并向用户显示一个显示状态的自动刷新页面,并带有进度条或其他一些花哨的视觉效果来保持它们从无聊。

于 2010-01-20T11:59:40.803 回答
2

请参阅 Randal Schwartz 的Watching long processes through CGI。本文使用 Perl,但该技术不依赖于语言。

于 2010-01-20T12:03:14.637 回答
2

Very similar question here. I suggest spawning off the lengthy process and returning an ajax based progress bar to the user. This way they user has the luxury of the web-interface and you have the luxury of no time-outs.

于 2010-01-20T12:06:52.507 回答
1

恕我直言,最好的方法是运行一个独立的脚本,在某处(平面文件、数据库等)发布更新。我不知道如何从 python 派生一个独立的进程,所以我不能给出任何代码示例。

要在网站上显示进度,请对读取这些状态更新的页面执行 ajax 请求,例如显示一个漂亮的进度条。

添加诸如 setTimeout("refreshProgressBar[...]) 或元刷新之类的内容以进行自动刷新。

于 2010-01-20T11:54:01.110 回答