diff --git a/lib/functions_framework/cli.rb b/lib/functions_framework/cli.rb index f6f00d71..6623dc12 100644 --- a/lib/functions_framework/cli.rb +++ b/lib/functions_framework/cli.rb @@ -36,6 +36,7 @@ def initialize @source = ::ENV["FUNCTION_SOURCE"] || ::FunctionsFramework::DEFAULT_SOURCE @env = nil @port = nil + @pidfile = nil @bind = nil @min_threads = nil @max_threads = nil @@ -67,6 +68,12 @@ def error? # attr_reader :error_message + ## + # @return [String] The pidfile. + # @return [nil] if not running. + # + attr_reader :pidfile + ## # Parse the given command line arguments. # Exits if argument parsing failed. @@ -89,6 +96,9 @@ def parse_args argv # rubocop:disable Metrics/MethodLength,Metrics/AbcSize "Supported values are 'http' and 'cloudevent'." do |val| @signature_type = val end + op.on "-P", "--pidfile PIDFILE", "Set the pidfile for the server (defaults to puma.pid)" do |val| + @pidfile = val + end op.on "-p", "--port PORT", "Set the port to listen to (defaults to 8080)" do |val| @port = val.to_i end @@ -218,6 +228,7 @@ def start_server ::FunctionsFramework.start function do |config| config.rack_env = @env config.port = @port + config.pidfile = @pidfile config.bind_addr = @bind config.show_error_details = @detailed_errors config.min_threads = @min_threads diff --git a/lib/functions_framework/server.rb b/lib/functions_framework/server.rb index 074ebccd..7660b514 100644 --- a/lib/functions_framework/server.rb +++ b/lib/functions_framework/server.rb @@ -152,6 +152,24 @@ def running? @server&.thread&.alive? end + ## + # Returns pidfile if server is currently running + # + # @return [String, nil] + # + def pidfile + @config.pidfile if running? + end + + ## + # Returns whether pidfile is present. + # + # @return [Boolean] + # + def pidfile? + !!@config.pidfile && running? + end + ## # Cause this server to respond to SIGTERM, SIGINT, and SIGHUP by shutting # down gracefully. @@ -214,6 +232,7 @@ def initialize self.rack_env = nil self.bind_addr = nil self.port = nil + self.pidfile = nil self.min_threads = nil self.max_threads = nil self.show_error_details = nil @@ -245,6 +264,14 @@ def port= port @port = (port || ::ENV["PORT"] || 8080).to_i end + ## + # Set the pidfile string, or `nil` to use the default. + # @param path [String,nil] + # + def pidfile= path + @pidfile = (path || ::ENV["PIDFILE"] || "puma.pid").to_s + end + ## # Set the minimum number of worker threads, or `nil` to use the default. # @param min_threads [Integer,nil] @@ -306,6 +333,14 @@ def port @port end + ## + # Returns the current pidfile string. + # @return [String] + # + def pidfile + @pidfile + end + ## # Returns the minimum number of worker threads in the thread pool. # @return [Integer] diff --git a/test/test_cli.rb b/test/test_cli.rb index 4c0d9fff..5e32f649 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -27,6 +27,7 @@ let(:retry_count) { 10 } let(:retry_interval) { 0.5 } let(:port) { "8066" } + let(:pidfile) { "server.pid" } let(:timeout) { 10 } def run_with_retry cli @@ -104,6 +105,21 @@ def run_in_timeout cli assert_equal "I received a request: GET http://127.0.0.1:#{port}/", response.body end + it "runs an http server with a pidfile" do + args = [ + "--source", http_source, + "--target", "simple_http", + "--port", port, + "--pidfile", pidfile, + "-q" + ] + cli = FunctionsFramework::CLI.new.parse_args args + _response = run_with_retry cli do + Net::HTTP.get_response URI("http://127.0.0.1:#{port}/") + end + assert_equal pidfile, cli.pidfile + end + it "runs an http server with a function that includes a return" do args = [ "--source", http_return_source, diff --git a/test/test_server.rb b/test/test_server.rb index 1bd678dc..6f79f573 100644 --- a/test/test_server.rb +++ b/test/test_server.rb @@ -38,6 +38,7 @@ end } let(:port) { 8077 } + let(:pidfile) { "server.pid" } let(:server_url) { "http://127.0.0.1:#{port}" } let(:quiet_logger) { logger = ::Logger.new $stderr @@ -56,6 +57,7 @@ def make_basic_server function, show_error_details: true config.min_threads = 1 config.max_threads = 1 config.port = port + config.pidfile = pidfile config.bind_addr = "127.0.0.1" config.rack_env = "development" config.logger = quiet_logger @@ -94,6 +96,19 @@ def query_server_with_retry server http_server.stop.wait_until_stopped timeout: 10 end + it "uses a pidfile" do + refute http_server.pidfile? + refute http_server.pidfile + http_server.start + assert http_server.pidfile? + assert http_server.pidfile + http_server.stop.wait_until_stopped timeout: 10 + refute http_server.running? + refute http_server.pidfile? + ensure + http_server.stop.wait_until_stopped timeout: 10 + end + it "handles post requests" do response = query_server_with_retry http_server do ::Net::HTTP.post URI("#{server_url}/"), "Hello, world!", "Content-Type" => "text/plain"