为什么热门部署Hypnotoad会重新运行旧的http请求?

时间:2018-02-01 19:24:00

标签: perl mojolicious hypnotoad

简而言之:
有时我会对Hypnotoad进行热部署,新服务器会立即处理已经由前一个服务器处理过的大量HTTP请求。

如果已呈现响应但线程仍在进行某些处理,Mojo / Hypnotoad是否会保留请求,直到处理停止为止?我是否需要告诉服务器HTTP请求已解决?

长版:
我有一个在Hypnotoad下运行的Mojolicious :: Lite应用程序。 该应用程序的功能是接受来自其他服务的HTTP请求。

我们正在处理通过一系列州进展的工作。 在每个作业状态更改时,将通过HTTP请求通知应用程序。 这是一个繁忙的小脚本 - 收到超过1000 req / hour。

脚本作业是操纵一些数据..进行数据库更新,编辑文件,发送邮件。

为了让事情继续前进,当它收到HTTP请求时,它会检查收到的数据。如果数据看起来很好,它会立即向调用者发送200响应,然后继续执行更耗时的任务。 (我猜这是根本原因)

当我热部署时 - 通过重新运行启动脚本(运行'localperl / bin / hypnotoad $ RELDIR / etc / bki / bki.pl') - 已经处理的一些请求被发送到新服务器并重新处理。

为什么这些旧交易仍由原始服务器持有?许多人已经很久没有完成了! 是否需要告诉Mojolicious请求是在它发生之前完成并且数据混乱? (我考虑过$ c-> finish(),但那只是套接字?) Hypnotoad如何决定应该将哪些请求传递给它的替换服务器?

以下是我正在做的一些伪代码:

get '/jobStateChange/:jobId/:jobState/:jobCause' => sub {
    my $c =shift;

    my $jobId = $c->stash("jobId");
    return $c->render(text => "invalid jobId: $jobId", status => 400) unless $jobId=~/^\d+$/;

    my $jobState = $c->stash("jobState");
    return $c->render(text => "invalid jobState: $jobState", status => 400) unless $jobState=~/^\d+$/;

    my $jobCause = $c->stash("jobCause");
    return $c->render(text => "invalid jobCause: $jobCause", status => 400) unless $jobCause=~/^\d+$/;

    my $jobLocation = $c->req->param('jobLocation');
    if ($jobLocation){ $jobLocation = $ENV{'DATADIR'} . "/jobs/" . $jobLocation; }
    unless ( $jobLocation && -d $jobLocation ){
        app->log->debug("determining jobLocation because passed job jobLocation isn't useable");
        $jobLocation = getJobLocation($jobId);
        $c->stash("jobLocation", $jobLocation);
    }

    # TODO - more validation? would BKI lie to us?
    return if $c->tx->res->code && 400 == $c->tx->res->code; # return if we rendered an error above

    # tell BKI we're all set ASAP
    $c->render(text => 'ok');
    handleJobStatusUpdate($c, $jobId, $jobState, $jobCause, $jobLocation);

};

sub handleJobStatusUpdate{
    my ($c, $jobId, $jobState, $jobCause, $jobLocation) = @_;
    app->log->info("job $jobId, state $jobState, cause $jobCause, loc $jobLocation");

    # set the job states in jobs
    app->work_db->do($sql, undef, @params);


    if ($jobState == $SOME_JOB_STATE) { 
        ... do stuff ...
        ... uses $c->stash to hold data used by other functions
    }

    if ($jobState == $OTHER_JOB_STATE) { 
        ... do stuff ...
        ... uses $c->stash to hold data used by other functions
    }
}

1 个答案:

答案 0 :(得分:1)

在请求处理程序返回之前,您的请求将不会完成。例如,这个小应用程序需要5秒钟才能输出" test":

# test.pl
use Mojolicious::Lite;
get '/test' => sub { $_[0]->render( text => "test" ); sleep 5 };
app->start;

您的应用的解决方法是在后台进程中运行handleJobStatusUpdate

get '/jobStateChange/:jobId/:jobState/:jobCause' => sub {
    my $c =shift;    
    my $jobId = $c->stash("jobId");
    my $jobState = $c->stash("jobState");
    my $jobCause = $c->stash("jobCause");
    my $jobLocation = $c->req->param('jobLocation');
    ...
    $c->render(text => 'ok');
    if (fork() == 0) {
        handleJobStatusUpdate($c, $jobId, $jobState, $jobCause, $jobLocation);
        exit;
    }