diff --git a/examples/hello/falcon.rb b/examples/hello/falcon.rb index ea6e757..303876f 100755 --- a/examples/hello/falcon.rb +++ b/examples/hello/falcon.rb @@ -20,10 +20,4 @@ # end # append preload "preload.rb" - - include Async::Container::Supervisor::Supervised -end - -service "supervisor" do - include Falcon::Environment::Supervisor end diff --git a/examples/supervisor/bake.rb b/examples/supervisor/bake.rb new file mode 100644 index 0000000..cb4d2ca --- /dev/null +++ b/examples/supervisor/bake.rb @@ -0,0 +1,9 @@ +def leak(size: 1024*1024) + require "async/http/internet/instance" + + Sync do + response = Async::HTTP::Internet.get("http://localhost:8080/?leak=#{size}") + ensure + response&.finish + end +end diff --git a/examples/supervisor/config.ru b/examples/supervisor/config.ru new file mode 100755 index 0000000..cb20584 --- /dev/null +++ b/examples/supervisor/config.ru @@ -0,0 +1,15 @@ +#!/usr/bin/env falcon --verbose serve -c +# frozen_string_literal: true + +leaks = [] + +run do |env| + request = Rack::Request.new(env) + + if size = request.params["leak"] + Console.debug(self) {"Leaking #{size} bytes..."} + leaks << " " * size.to_i + end + + [200, {}, ["Hello World"]] +end diff --git a/examples/supervisor/falcon.rb b/examples/supervisor/falcon.rb new file mode 100755 index 0000000..8e86114 --- /dev/null +++ b/examples/supervisor/falcon.rb @@ -0,0 +1,62 @@ +#!/usr/bin/env falcon-host +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2019-2024, by Samuel Williams. + +require "falcon/environment/self_signed_tls" +require "falcon/environment/rack" +require "falcon/environment/supervisor" + +class MemoryMonitor < Async::Container::Supervisor::MemoryMonitor + def memory_leak_detected(process_id, monitor) + connections = @processes[process_id] + + # Note that if you use a multi-threaded or hybrid container, there will be multiple connections per process. We break after the first successful dump. + connections.each do |connection| + response = connection.call(do: :memory_dump, path: "memory-#{process_id}.json", timeout: 30) + Console.info(self, "Memory dumped...", response: response) + + break + end + + super + end +end + +service "hello.localhost" do + include Falcon::Environment::SelfSignedTLS + include Falcon::Environment::Rack + + scheme "http" + protocol {Async::HTTP::Protocol::HTTP} + + endpoint do + Async::HTTP::Endpoint.for(scheme, "localhost", port: 9292, protocol: protocol) + end + + count 4 + + url "http://localhost:8080" + + endpoint do + ::Async::HTTP::Endpoint.parse(url).with(**endpoint_options) + end + + include Async::Container::Supervisor::Supervised +end + +service "supervisor" do + include Falcon::Environment::Supervisor + + monitors do + [ + MemoryMonitor.new(interval: 10, + # Per-supervisor (cluster) limit: + total_size_limit: 80*1024*1024, + # Per-process limit: + maximum_size_limit: 20*1024*1024 + ) + ] + end +end diff --git a/examples/supervisor/preload.rb b/examples/supervisor/preload.rb new file mode 100644 index 0000000..8598526 --- /dev/null +++ b/examples/supervisor/preload.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# Released under the MIT License. +# Copyright, 2020-2024, by Samuel Williams. + +# $stderr.puts "Preloading..." diff --git a/gems.rb b/gems.rb index 29b0f25..76ce08e 100644 --- a/gems.rb +++ b/gems.rb @@ -22,6 +22,7 @@ # gem "protocol-rack", path: "../protocol-rack" # gem "async-service", path: "../async-service" # gem "io-stream", path: "../io-stream" +# gem "memory-leak", path: "../memory-leak" # gem "fiber-profiler"