#!/usr/bin/env perl # run as www-data (same as /run/hilis4/*.pid owner) # perl script/kidreaper.pl # adapted from http://www.catalystframework.org/calendar/2007/18: # * changed kB to MB # * used IPC::System::Simple to capture ppid from service-name # can be run as JUST_TESTING by omitting max_mem (ARGV[1]) #============================================================================== my $JUST_TESTING = 0; # reports to command-line, doesn't kill processes #============================================================================== use lib '/home/raj/perl5/lib/perl5'; use IPC::System::Simple qw(capture); use DateTime::Format::Strptime; use Data::Printer; use Modern::Perl; my $service_names = $ARGV[0] or die "Usage: $0 []\n"; my $max_mb = $ARGV[1]; # optional - if empty, switches to JUST_TESTING and sets default 1000 #============================================================================== $JUST_TESTING = 1 if ! $max_mb; # warn $JUST_TESTING; #============================================================================== $max_mb ||= 1000; # warn $max_mb; warn $service_names; my @services = split ',', $service_names; # p @services; my $formatter = DateTime::Format::Strptime->new(pattern => '%F %T'); for my $service (@services) { my $ppid = capture("cat /run/hilis4/$service.pid") or die $!; # warn $ppid; exit; my $cmd = sprintf '/bin/ps -o pid=,vsz= --ppid %s|', $ppid; if ( open (my $kids, $cmd) ) { my @goners = (); while (<$kids>) { chomp; my ($pid, $mem) = split; # p $mem; # ps shows KB. we want MBytes. $mem /= 1024; if ($mem >= $max_mb) { push @goners, { name => $service, pid => $pid, mem => $mem }; if ($JUST_TESTING) { say sprintf "process %s mem [%s MB] > permitted [%s MB]", $pid, $mem, $max_mb; } } } close($kids); if (@goners and not $JUST_TESTING) { # kill them slowly, so that they don't all suddenly die at once: foreach my $victim (@goners) { # p $victim; kill 'HUP', $victim->{pid}; # send Signal HangUp _log($victim); sleep 10; } } } else { my $time = _get_time(); say "$time | can't get process list for $service [$ppid]: $!"; } } sub _log { # kidreaper.log: my $data = shift; say sprintf '%s | %s process %s mem %sMB > permitted %sMB', _get_time(), uc $data->{name}, $data->{pid}, int $data->{mem}, $max_mb; } sub _get_time { my $time = DateTime->now; $time->set_formatter($formatter); # warn $time; return $time; }