]> wagnertech.de Git - kivitendo-erp.git/commitdiff
FCGI: Prozess nach Request beenden, falls belegter Speicher größer als konfigurierbar...
authorMoritz Bunkus <m.bunkus@linet-services.de>
Thu, 17 Dec 2015 10:56:09 +0000 (11:56 +0100)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Thu, 17 Dec 2015 10:56:09 +0000 (11:56 +0100)
Perl gibt Speicher nicht wieder ans Betriebssystem zurück. Um zu
erreichen, dass nach einigen sehr speicherintensiven Aktionen der Server
nicht zu swappen anfangen muss, kann der Administrator nun in der
Konfigurationsdatei Limits für den Speicherverbrauch definieren.

Werden diese Limits erreicht, so beendet sich der aktuelle
Prozess. Diese Prüfung wird erst nach vollständiger Abarbeitung eines
Requests durchgeführt. Der FCGI-Manager startet dann bei der nächsten
Anfrage automatisch einen neuen Prozess.

config/kivitendo.conf.default
dispatcher.fpl

index 4242d65b1ed79709f01593e9c3f6c4737d8f29cf..1639849154637b3f5cd5cbc4d645d420c7fc2bf8 100644 (file)
@@ -65,6 +65,21 @@ bind_password =
 # and "en" (English, not perfect) are available.
 language = de
 
+# The memory limits given here determine the maximum process size
+# (vsz, the total amount of memory this process uses including memory
+# swapped out or shared with other processes) or resident set size
+# (rss, the amount of memory not swapped out/shared with other
+# processes). If either limit is reached at the end of the request
+# then the kivitendo process will exit.
+#
+# This only makes sense when running under FCGI. The FCGI manager will
+# then automatically start a new process.
+#
+# Numbers can be postfixed with KB, MB, GB. If no number is given or
+# the number is 0 then no checking will be performed.
+memory_limit_rss =
+memory_limit_vsz =
+
 [paths]
 # path to temporary files (must be writeable by the web server)
 userspath = users
index 7d2dfb5be9f4bfce7adb8870c0453c46a030e5af..5e384ce68c3639396569e7fa02db8001b28c3979 100755 (executable)
@@ -3,8 +3,58 @@
 use strict;
 
 use FCGI;
+use IO::File;
 use SL::Dispatcher;
 use SL::FCGIFixes;
+use SL::LXDebug;
+
+sub _parse_number_with_unit {
+  my ($number) = @_;
+
+  return undef   unless defined $number;
+  return $number unless $number =~ m{^ \s* (\d+) \s* ([kmg])b \s* $}xi;
+
+  my %factors = (K => 1024, M => 1024 * 1024, G => 1024 * 1024 * 1024);
+
+  return $1 * $factors{uc $2};
+}
+
+sub _memory_usage_is_too_high {
+  return undef unless $::lx_office_conf{system};
+
+  my %limits = (
+    rss  => _parse_number_with_unit($::lx_office_conf{system}->{memory_limit_rss}),
+    size => _parse_number_with_unit($::lx_office_conf{system}->{memory_limit_vsz}),
+  );
+
+  # $::lxdebug->dump(0, "limits", \%limits);
+
+  return undef unless $limits{rss} || $limits{vsz};
+
+  my %usage;
+
+  my $in = IO::File->new("/proc/$$/status", "r") or return undef;
+
+  while (<$in>) {
+    chomp;
+    $usage{lc $1} = _parse_number_with_unit($2) if m{^ vm(rss|size): \s* (\d+ \s* [kmg]b) \s* $}ix;
+  }
+
+  $in->close;
+
+  # $::lxdebug->dump(0, "usage", \%usage);
+
+  foreach my $type (keys %limits) {
+    next if !$limits{$type};
+    next if $limits{$type} >= ($usage{$type} // 0);
+
+    $::lxdebug->message(LXDebug::WARN(), "Exiting due to memory size limit reached for type '${type}': limit " . $limits{$type} . " bytes, usage " . $usage{$type} . " bytes");
+
+    return 1;
+  }
+
+  return 0;
+}
 
 our $dispatcher = SL::Dispatcher->new('FastCGI');
 $dispatcher->pre_startup_setup;
@@ -12,6 +62,9 @@ SL::FCGIFixes::apply_fixes();
 $dispatcher->pre_startup_checks;
 
 my $request = FCGI::Request();
-$dispatcher->handle_request($request) while $request->Accept() >= 0;
+while ($request->Accept() >= 0) {
+  $dispatcher->handle_request($request);
+  exit if _memory_usage_is_too_high();
+}
 
 1;