为什么热部署 Hypnotoad 会重新运行旧的 http 请求?
Why would hot deploy of Hypnotoad rerun old http requests?
简而言之:
当我热部署 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
}
}
直到请求处理程序returns,您的请求才会完成。例如,这个小应用程序需要 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;
}
简而言之:
当我热部署 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
}
}
直到请求处理程序returns,您的请求才会完成。例如,这个小应用程序需要 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;
}