diff --git a/falcon.gemspec b/falcon.gemspec index 2f80577..8caee5c 100644 --- a/falcon.gemspec +++ b/falcon.gemspec @@ -31,7 +31,7 @@ Gem::Specification.new do |spec| spec.add_dependency "async-container-supervisor", "~> 0.6" spec.add_dependency "async-http", "~> 0.75" spec.add_dependency "async-http-cache", "~> 0.4" - spec.add_dependency "async-service", "~> 0.10" + spec.add_dependency "async-service", "~> 0.16" spec.add_dependency "bundler" spec.add_dependency "localhost", "~> 1.1" spec.add_dependency "openssl", "~> 3.0" diff --git a/lib/falcon/environment/server.rb b/lib/falcon/environment/server.rb index 821b7a4..c2169dc 100644 --- a/lib/falcon/environment/server.rb +++ b/lib/falcon/environment/server.rb @@ -3,7 +3,7 @@ # Released under the MIT License. # Copyright, 2020-2025, by Samuel Williams. -require "async/service/generic" +require "async/service/managed_environment" require "async/http/endpoint" require_relative "../service/server" @@ -13,6 +13,8 @@ module Falcon module Environment # Provides an environment for hosting a web application that uses a Falcon server. module Server + include Async::Service::ManagedEnvironment + # The service class to use for the proxy. # @returns [Class] def service_class @@ -25,21 +27,6 @@ def authority self.name end - # Number of instances to start. By default (when nil), uses `Etc.nprocessors`. - # @returns [Integer | nil] - def count - nil - end - - # Options to use when creating the container. - def container_options - { - restart: true, - count: self.count, - health_check_timeout: 30, - }.compact - end - # The host that this server will receive connections for. def url "http://[::]:9292" @@ -80,13 +67,6 @@ def client_endpoint ::Async::HTTP::Endpoint.parse(url) end - # Any scripts to preload before starting the server. - # - # @returns [Array(String)] The list of scripts to preload. - def preload - [] - end - # Make a server instance using the given endpoint. The endpoint may be a bound endpoint, so we take care to specify the protocol and scheme as per the original endpoint. # # @parameter endpoint [IO::Endpoint] The endpoint to bind to. diff --git a/lib/falcon/service/server.rb b/lib/falcon/service/server.rb index a5f2dc9..68ddd16 100644 --- a/lib/falcon/service/server.rb +++ b/lib/falcon/service/server.rb @@ -4,7 +4,7 @@ # Copyright, 2019-2025, by Samuel Williams. # Copyright, 2020, by Daniel Evans. -require "async/service/generic" +require "async/service/managed_service" require "async/container/supervisor/supervised" require "async/http/endpoint" @@ -12,28 +12,13 @@ module Falcon module Service - class Server < Async::Service::Generic + class Server < Async::Service::ManagedService def initialize(...) super @bound_endpoint = nil end - # Preload any resources specified by the environment. - def preload! - root = @evaluator.root - - if scripts = @evaluator.preload - scripts = Array(scripts) - - scripts.each do |path| - Console.logger.info(self) {"Preloading #{path}..."} - full_path = File.expand_path(path, root) - load(full_path) - end - end - end - # Prepare the bound endpoint for the server. def start @endpoint = @evaluator.endpoint @@ -42,47 +27,42 @@ def start @bound_endpoint = @endpoint.bound end - preload! - Console.logger.info(self) {"Starting #{self.name} on #{@endpoint}"} super end - # Setup the container with the application instance. - # @parameter container [Async::Container::Generic] - def setup(container) - container_options = @evaluator.container_options - health_check_timeout = container_options[:health_check_timeout] + # Run the service logic. + # + # @parameter instance [Object] The container instance. + # @parameter evaluator [Environment::Evaluator] The environment evaluator. + # @returns [Falcon::Server] The server instance. + def run(instance, evaluator) + if evaluator.key?(:make_supervised_worker) + Console.warn(self, "Async::Container::Supervisor is replaced by Async::Services::Supervisor, please update your service definition.") + + evaluator.make_supervised_worker(instance).run + end + + server = evaluator.make_server(@bound_endpoint) - container.run(name: self.name, **container_options) do |instance| - evaluator = @environment.evaluator + Async do |task| + server.run - Async do |task| - if @environment.implements?(Async::Container::Supervisor::Supervised) - evaluator.make_supervised_worker(instance).run - end - - server = evaluator.make_server(@bound_endpoint) - - server.run - - instance.ready! - - if health_check_timeout - Async(transient: true) do - while true - # We only update this if the health check is enabled. Maybe we should always update it? - instance.name = "#{self.name} (#{server.statistics_string} L=#{Fiber.scheduler.load.round(3)})" - sleep(health_check_timeout / 2) - instance.ready! - end - end - end - - task.children.each(&:wait) - end + task.children.each(&:wait) end + + server + end + + # Format the process title with server statistics. + # + # @parameter evaluator [Environment::Evaluator] The environment evaluator. + # @parameter server [Falcon::Server] The server instance. + # @returns [String] The formatted process title. + private def format_title(evaluator, server) + load = Fiber.scheduler.load.round(3) + "#{evaluator.name} (#{server.statistics_string} L=#{load})" end # Close the bound endpoint.