这是我的第一个Catalyst应用程序,我不知道如何解决以下问题。
用户在表单中输入一些数据并选择一个文件(最多100MB)进行上传。提交表单后,实际计算最多需要5分钟,结果存储在数据库中。
我想要做的是在后台中运行此过程(也可能是文件上传)以避免服务器超时。应该向用户提供某种反馈(例如消息“已启动作业”或进度条)。作业仍在运行时应该阻止表单。作业完成后,应显示结果页面。
在几小时的阅读中,我偶然发现了异步请求,作业队列,守护进程,Gearman或Catalyst::Plugin::RunAfterRequest等概念。
你会怎么做? 感谢您帮助网络开发新手!
PS:在我当前的本地应用程序中,工作与 Parallel :: ForkManager 并行完成。对于真正的应用程序,建议使用像Amazon EC2这样的云计算服务吗?或者只是找一个提供多核服务器的主机?
答案 0 :(得分:1)
将作业放入队列中,并在Web应用程序之外的其他进程中执行此操作。当您的Catalyst进程繁忙时,即使使用Catalyst :: Plugin :: RunAfterRequest,它也不能用于处理其他Web请求。
有非常简单的排队系统,例如File::Queue。基本上,您将作业ID分配给文档,并将其放入队列中。另一个进程检查队列并获取新作业。
您可以将作业状态保存在数据库中,也可以将任何Web应用程序中的任何内容保存。在前端,您可以每X秒或几分钟轮询一次作业状态,以便向用户提供反馈。
你必须弄清楚你需要多少内存和CPU。即使您有多个进程在运行,也可能不需要多核CPU或多个CPU。在EC2之类的专用服务器或云之间进行选择更多的是关于灵活性(调整大小,快照等)与价格的关系。
答案 1 :(得分:1)
不知怎的,我无法理解File :: Queue。对于非阻塞并行执行,我最终使用了TheSchwartz和Parallel :: Prefork的组合,就像它在Foorum Catalyst App中实现的那样。 基本上,有5个重要元素。也许这个摘要对其他人有帮助。
2)TheSchwartz DB的客户端(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)在Catalyst控制器中:将新作业插入表作业并传递一些参数
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")}
)
);
}
新的运行在“存档”页面上显示为灰色,直到数据库中的所有结果都可用。