2017-01-19 43 views
3

这是我的第一个Catalyst应用程序,我不确定如何解决以下问题。如何在Catalyst应用程序中管理长时间运行的进程?

用户在表单中输入一些数据并选择一个文件(最大100MB)上传。提交表单后,实际计算最多需要5分钟,结果存储在数据库中。

我想要做的是在背景中运行此过程(也可能是文件上载)以避免服务器超时。应该有一些反馈给用户(比如“作业已经启动”或进度条)。表单在作业仍在运行时应该被阻止。作业完成后应显示结果页面。

在阅读的小时内,我偶然发现了异步请求,作业队列,守护进程,GearmanCatalyst::Plugin::RunAfterRequest等概念。

你会怎么做? 感谢您帮助网页开发新手!

PS:在我当前的本地应用程序中,工作与并行:: ForkManager并行完成。对于真正的应用程序,使用像Amazon EC2这样的云计算服务是否明智?或者只是找到一个提供多核服务器的托管商?

+3

做上传作为异步请求是有道理的。返回一个作业ID,并在Action完成后在Action中设置一个标志。然后让你的页面定期异步地轮询后端(比如每10秒),如果它获得_done_,则刷新页面。我会稍微输入一个答案。 – simbabque

+0

关于您的主机托管问题,它实际上取决于用例。亚马逊或其他云服务的优势在于,如果需要,可以轻松扩展,但除了其他考虑事项外,可能比拥有自己的服务器更昂贵。这个问题应该最好单独和其他地方发布。 – bytepusher

+0

@simbabque如果您有时间,有用的工具/插件提示或一些示例代码会非常有帮助。 感谢bytepusher,我会考虑应用程序投入生产时 –

回答

1

将作业放入队列中,并在Web应用程序之外的其他进程中执行此作业。虽然Catalyst进程很忙,即使使用Catalyst :: Plugin :: RunAfterRequest,也不能用于处理其他Web请求。

有非常简单的排队系统,如File::Queue。基本上,您为文档分配一个作业ID,将其放入队列中。另一个过程检查队列并提取新的作业。

您可以将作业状态保存在数据库或任何可以访问的任何Web应用程序中。在前端,您可以每隔X秒或几分钟轮询一次作业状态,以向用户提供反馈。

你必须弄清楚你需要多少内存和CPU。即使您有多个进程在运行,也可能不需要多核CPU或多个CPU。在EC2之类的专用服务器或云之间进行选择更多是关于灵活性(调整大小,快照等)与价格之间的关系。

+0

这几乎是我想说的。 – simbabque

+0

感谢您的建议Julien。我是使用Perl来处理“复杂”网络应用程序的新手。我无法弄清楚如何使用File :: Queue。你介意写一些示例代码排队和轮询的催化剂? 除此之外,你认为我可以使用TheSchwartz来适应这种情况:http://fayland.me/perl/2007/10/04/use-theschwartz-job-queue-to-handle/? –

+0

File :: Queue的文档有例子:http://search.cpan.org/perldoc?File%3A%3AQueue – Julien

1

不知何故,我无法得到File :: Queue的想法。对于非阻塞并行执行,我最终使用了TheSchwartz和Parallel :: Prefork的组合,就像它在Foorum Catalyst App中执行的那样。基本上,有5个重要元素。也许这个总结会对别人有帮助。

1)TheSchwartz DB

2)客户端(DB句柄)的TheSchwartz DB

package MyApp::TheSchwartz::Client; 

use TheSchwartz;  
sub theschwartz { 
    my $theschwartz = TheSchwartz->new(
     databases => [ { 
      dsn => 'dbi:mysql:theschwartz', 
      user => 'user', 
      pass => 'pass', 
     } ], 
     verbose => 1, 
    ); 
    return $theschwartz; 
} 

3)作业工人(其中实际工作已经完成)

package MyApp::TheSchwartz::Worker::Test; 

use base qw(TheSchwartz::Moosified::Worker); 
use MyApp::Model::DB;  # Catalyst DB connect_info 
use MyApp::Schema;   # Catalyst DB schema 

sub work { 
    my $class = shift; 
    my $job = shift;  
    my ($args) = $job->arg; 
    my ($arg1, $arg2) = @$args; 

    # re-use Catalyst DB schema  
    my $connect_info = MyApp::Model::DB->config->{connect_info}; 
    my $schema = MyApp::Schema->connect($connect_info); 

    # do the heavy lifting 

    $job->completed(); 
} 

4)工作进程TheSchwartzWorker.pl,其监视表工作不停止

use MyApp::TheSchwartz::Client qw/theschwartz/; # db connection 
use MyApp::TheSchwartz::Worker::Test; 
use Parallel::Prefork; 

my $client = theschwartz(); 

my $pm = Parallel::Prefork->new({ 
    max_workers => 16, 
    trap_signals => { 
     TERM => 'TERM', 
     HUP => 'TERM', 
     USR1 => undef, 
    } 
}); 

while ($pm->signal_received ne 'TERM') { 
    $pm->start and next; 

    $client->can_do('MyApp::TheSchwartz::Worker::Test');  
    my $delay = 10; # When no job is available, the working process will sleep for $delay seconds 
    $client->work($delay); 

    $pm->finish; 
}  
$pm->wait_all_children(); 

5)在催化剂控制:插入一个新的工作到表工作和传递一些参数

use MyApp::TheSchwartz::Client qw/theschwartz/; 
sub start : Chained('base') PathPart('start') Args(0) { 
    my ($self, $c) = @_; 

    $client = theschwartz(); 
    $client->insert(‘MyApp::TheSchwartz::Worker::Test’, [ $arg1, $arg2 ]); 

    $c->response->redirect(
     $c->uri_for(
      $self->action_for('archive'), 
      {mid => $c->set_status_msg("Run '$name' started")} 
     ) 
    ); 
} 

新的运行是灰色的“档案”页面上,直到所有的结果都可以在数据库中。

相关问题