Make memory limits configurable and make them work with passenger
authorTom Hughes <tom@compton.nu>
Mon, 19 Jul 2010 17:01:42 +0000 (18:01 +0100)
committerTom Hughes <tom@compton.nu>
Mon, 19 Jul 2010 17:01:42 +0000 (18:01 +0100)
config/application.yml
config/initializers/limits.rb [deleted file]
config/initializers/memory_limits.rb [new file with mode: 0644]

index 1b38f8f746e8108a879c9ccde97a95f89defe6a2..95037f83ecfc3f85a432273e051e38f04ae6dd9a 100644 (file)
@@ -28,7 +28,10 @@ standard_settings: &standard_settings
   spam_threshold: 50
   # Default legale (jurisdiction location) for contributor terms
   default_legale: GB
+  # Memory limits (in Mb)
+  #soft_memory_limit: 512
+  #hard_memory_limit: 2048 
+
 development:
   <<: *standard_settings
 
diff --git a/config/initializers/limits.rb b/config/initializers/limits.rb
deleted file mode 100644 (file)
index 9862036..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-# Set a hard limit of 1Gb on the virtual size of the process
-if Process.const_defined?(:RLIMIT_AS)
-  Process.setrlimit Process::RLIMIT_AS, 1024*1024*1024, Process::RLIM_INFINITY
-end
diff --git a/config/initializers/memory_limits.rb b/config/initializers/memory_limits.rb
new file mode 100644 (file)
index 0000000..bab94b0
--- /dev/null
@@ -0,0 +1,44 @@
+# Setup any specified hard limit on the virtual size of the process
+if APP_CONFIG.include?('hard_memory_limit') and Process.const_defined?(:RLIMIT_AS)
+  Process.setrlimit Process::RLIMIT_AS, APP_CONFIG['hard_memory_limit']*1024*1024, Process::RLIM_INFINITY
+end
+
+# If we're running under passenger and a soft memory limit is
+# configured then setup some rack middleware to police the limit
+if APP_CONFIG.include?('soft_memory_limit') and defined?(PhusionPassenger)
+  # Define some rack middleware to police the soft memory limit
+  module OSM
+    class MemoryLimit
+      def initialize(app)
+        @app = app
+      end
+
+      def call(env)
+        # Process this requst
+        status, headers, body = @app.call(env)
+
+        # Restart if we've hit our memory limit
+        if resident_size > APP_CONFIG['soft_memory_limit']
+          Process.kill("USR1", 0)
+        end
+
+        # Return the result of this request
+        [status, headers, body]
+      end
+      private
+      def resident_size
+        # Read statm to get process sizes. Format is
+        #   Size RSS Shared Text Lib Data
+        fields = File.open("/proc/self/statm") do |file|
+          fields = file.gets.split(" ")
+        end
+
+        # Return resident size in megabytes
+        return fields[1].to_i / 256
+      end
+    end
+  end
+
+  # Install the memory limit checker
+  Rails.configuration.middleware.use OSM::MemoryLimit
+end