2011-05-06 70 views
3

我正在开发一个ruby CGI视频处理工具,并且希望在用户点击启动ffmpeg for a-hour-long-encoding-spree按钮时将用户重定向到另一个位置。Ruby CGI重定向响应,无需等待脚本结束

下面是代码:

@cgi.out("status" => "302", "location" => @job.report_url) {''} 
@cgi.out{''} 
@job.start 

做这样的工作正常的Safari 5.0.5。但是Firefox在重定向之前等待脚本完成他的工作。而且,如果你的脚本比Apache的超时花费更长的时间,那么它可能永远不会发生。

我希望得到一个cgi.close()方法。哪存在!但是是一个CGI :: Session方法,对我来说无关紧要。

这是另一个类似的问题......但不是重复的!因为我需要使用标准输入,输出和错误重定向:Returning a response with Ruby CGI before script is finished?

所以,我怎么能发送一个完整CGI响应之前做一些其他的任务,并具有相同的脚本?

+0

试着做@ cgi.send(:stdoutput).flush – Roman 2011-05-09 23:56:01

回答

1

那么,终于明白了。

但它看起来更像是一个黑客不是一个真正的解决方案:

@cgi.out("status" => "303", "Connection" => "close", "Content-Length" => 1, "Location" => @job.report_url) {' '} 
@job.start 

有两个关键的东西,使其工作,既需要:

  1. 设置Content-Lenght的东西大于0. 1适用于一个内容空间。
  2. Connection设置为close。这很尴尬,因为这在理论上可以在HTTP 1.1 Keep Alive连接中正常工作。但是,这似乎触发页面呈现在Firefox 4

我切换到作业提交的POST请求(HTTP 303)后更正确的303 See Other响应。但是这不起作用,302响应也很有效。

+0

需要连接关闭,因为连接不由CGI脚本处理,由服务器处理并在CGI脚本终止之前保持打开状态。另外,Content-Length:1也很奇怪。内容长度:0没有内容应该正常工作。 – 2011-05-10 16:46:41

+0

您可以尝试关闭stdout(服务器端连接关闭),而不是设置Connection:close(客户端连接关闭)。这将在理论上起作用,但我不确定。 – 2011-05-10 16:50:42

1

解决这类问题的常用方法是将应用程序分成两个进程。

  1. 的CGI部分
  2. 处理部分

通常处理部分是等待来自众多CGI部分消息的应用的一个实例。 cgi部分只是将请求提交给处理部分。通信可以完成,只要你喜欢,但通常使用作业/消息队列完成。

这种方式一旦作业被提交到队列中,您可以重定向用户,并且处理部分最终将转到您的视频转码。

另一个优点是,一堆同时发生的请求不会使您的机器超负荷并发数十个并发转码操作。您还可以相对容易地将处理部件移动到一台或多台机器(取决于您选择的通信形式)/

快速web search将向您展示几十个示例。

+0

这确实是解决这类问题的正确方法。但是,由于这个应用程序具有非常轻巧且内部的用途,编写完整的作业队列系统可能有点矫枉过正。 – Arko 2011-05-09 10:46:57

+0

我不会尝试编写一个完整的作业队列系统,大多数我看到的例子只有很少的用户代码行,其余的是使用现有的作业队列系统。这两个似乎是赞成红宝石的人群:https://github.com/tobi/delayed_job https://github.com/defunkt/resque – 2011-05-10 00:10:52

+0

你绝对是对的。我会尝试他们两个。你得到赏金,因为这是解决这个问题的正确方法。 – Arko 2011-05-10 08:25:14

1

某些浏览器(如Firefox)在处理数据之前填充缓冲区。

@cgi.out("status" => "302", "location" => @job.report_url) { ' ' * 4096 } 
@job.start 

UPDATE:这里是我完整的测试代码:

#!/usr/bin/ruby 

require 'cgi' 

# change the line below to test; e.g.: buf = '' 
buf = ' ' * 4096 

cgi = CGI.new 
cgi.out('status' => '302', 'location' => 'http://www.example.com') { buf } 

sleep 10 

puts 'end' 

显然,'end'永远不会出现,因为

在家里测试中,我通过发送4096位的伎俩浏览器之前已被重定向。

buf为空时,Firefox在重定向前等待10秒钟。当它“满”(即,空间为4K)时,浏览器会立即重定向。在Ubuntu 10中使用Firefox 4.0进行测试。04和Windows 7中的Firefox 4.0.1。

+0

无法使用Firefox 4.0.1。也许你在哪里使用FF 3.6? – Arko 2011-05-09 09:32:50

+0

我更新了我的答案。也许在我的代码中的“睡眠”正在改变?当浏览器和Apache运行在同一台机器上时,它允许更多的并发性,除了现代计算机容易并行处理。无论如何,我建议你用我的代码进行测试,并尝试适应你的情况(如果我的代码有效 - 请告诉我,如果没有)。 – 2011-05-09 12:55:21

+0

在单独的服务器上使用Apache 2.2.17的Mac OS X 10.6上的FF 4.0.1仍然不起作用。但是谢谢你的时间! – Arko 2011-05-10 08:25:36

1

而不是发送一个空的缓冲区,尝试设置Content-Length标头为0. 对于关闭请求处理,内核#分叉应该有所帮助。

经过一点点的测试。这是需要做的。 Content-Length由cgi.out正确设置。您只需要传递一个空字符串将其设置为0.

另外,正如我在注释中所述,关闭标准输出有效关闭连接服务器端。 我用lighttpd + ree用firefox和chrome测试了这段代码。

require 'cgi'  
cgi = CGI.new 
cgi.out('status' => '302', 'location' => 'http://www.google.com') { "" } 
$stdout.close 

# here we do a very very long task 
sleep 30 
exit 0 
+0

不起作用。但是你让我走在正确的轨道上,谢谢。将Content-Length标头指定为大于0的内容。 – Arko 2011-05-10 08:26:06