Proposal:Search Throttling
From MovableType
THIS HAS BEEN IMPLEMENTED IN MT 4.15
mt-search.cgi needs a way to throttle requests. Here is a proposal of the throttling implementation for now before app-level throttling architecture would be established.
It throttles by sigalarm by default.
- MT::App::Search::throttle_control calls prepare_throttle callback.
- by default, a callback whose priority is set to 5 checks the request just like the legacy mt-search did before. If it did not satisfy, it sets up 5 seconds alarm before die-ing.
- MT::App::Search processes request.
- If alarm fires, it dies with "Throttled" message.
- If alarm does not fire before the request successfully processed, take_down callback resets alarm.
Developers can write a plugin to change how to throttle like below. The plugin sets up two throttle controllers.
- cb1 callback checks load average via uptime command. If the load is over the specified metric, it returns "0", by which MT::App::Search::throttle_control returns throttled response immediately.
- cb2 callback sets up sigalarm in 20 seconds, instead of the default 5 seconds.
- Both callbacks and the default callback respects priority, in that it does not do anything if $$result already had a value (which means higher priority callback already processed).
package MT::Plugin::SearchThrottle1;
use strict;
use MT 4;
use base 'MT::Plugin';
our $VERSION = '1.0';
my $plugin = MT::Plugin::SearchThrottle1->new({
name => "SearchThrottle1",
version => $VERSION,
registry => {
callbacks => {
'cb1' => {
callback => 'MT::App::Search::prepare_throttle',
handler => \&throttle_by_uptime,
priority => 3,
},
'cb2' => {
callback => 'MT::App::Search::prepare_throttle',
handler => \&throttle_by_sigalarm,
priority => 4,
}
},
},
});
MT->add_plugin($plugin);
sub throttle_by_uptime {
my ( $cb, $app, $result, $messages ) = @_;
# Don't bother if a callback proiritized higher
# set up its throttle already
return $$result if defined $$result;
my $uptime = `uptime`;
my @uptime = split ',', $uptime;
my $up5 = $uptime[3];
chomp $up5;
if ( $up5 > 0.1 ) {
push @$messages, $app->translate('Under heavy load');
$$result = 0;
}
1;
}
sub throttle_by_sigalarm {
my ( $cb, $app, $result, $messages ) = @_;
# Don't bother if a callback proiritized higher
# set up its throttle already
return $$result if defined $$result;
$SIG{ALRM} = sub { $app->errtrans('Too busy. Sorry.'); die; };
$app->{__have_throttle} = 1;
alarm(20);
$$result = 1;
1;
}
1;