lib/bbk/app/dispatcher.rb in bbk-app-1.0.0.152254 vs lib/bbk/app/dispatcher.rb in bbk-app-1.1.0.199383

- old
+ new

@@ -8,10 +8,12 @@ require 'bbk/utils/proxy_logger' module BBK module App + class InvalidAnswersMessagesCountError < StandardError; end + class SimplePoolFactory def self.call(pool_size, queue_size) BBK::App::ThreadPool.new(pool_size, queue: queue_size) end @@ -30,11 +32,12 @@ class Dispatcher attr_accessor :force_quit attr_reader :consumers, :publishers, :observer, :middlewares, :logger - ANSWER_DOMAIN = 'answer' + ANSWER_DOMAIN = 'answer'.freeze + DEFAULT_PROTOCOL = 'default'.freeze def initialize(observer, pool_size: 3, logger: BBK::App.logger, pool_factory: SimplePoolFactory, stream_strategy: QueueStreamStrategy) @observer = observer @pool_size = pool_size logger = logger.respond_to?(:tagged) ? logger : ActiveSupport::TaggedLogging.new(logger) @@ -50,13 +53,24 @@ def register_consumer(consumer) consumers << consumer end def register_publisher(publisher) + raise "Publisher support #{DEFAULT_PROTOCOL}" if publisher.protocols.include?(DEFAULT_PROTOCOL) publishers << publisher end + # set default publisher for results with empty scheme or DEFAULT_PROTOCOL scheme + def default_publisher=(publisher) + @default_publisher = publisher + end + + # get default publisher + def default_publisher + @default_publisher || (publishers.size == 1 ? publishers.first : nil) + end + def register_middleware(middleware) middlewares << middleware end # Run all consumers and blocks on message processing @@ -120,23 +134,24 @@ build_processing_stack.call(message).select do |r| r.is_a?(BBK::App::Dispatcher::Result) end end + # process one message and sending existed results messages + def process(message) + results = execute_message(message) + logger.debug "There are #{results.count} results to send from #{message.headers[:message_id]}..." + send_results(message, results).value + rescue StandardError => e + logger.error "Failed processing message: #{e.inspect}" + ActiveSupport::Notifications.instrument 'dispatcher.exception', msg: message, exception: e + message.nack(error: e) + close if force_quit + end + protected - def process(message) - results = execute_message(message) - logger.debug "There are #{results.count} results to send from #{message.headers[:message_id]}..." - send_results(message, results).value - rescue StandardError => e - logger.error "Failed processing message: #{e.inspect}" - ActiveSupport::Notifications.instrument 'dispatcher.exception', msg: message, exception: e - message.nack(error: e) - close if force_quit - end - def process_message(message) matched, processor = find_processor(message) results = [] begin is_unknown = @observer.instance_variable_get('@default') == processor @@ -174,12 +189,16 @@ end def send_results(incoming, results) message_id = incoming.headers[:message_id] - answer = results.find {|msg| msg.route.domain == ANSWER_DOMAIN } - Concurrent::Promises.zip_futures(*results.map do |result| + answers, sended_messages = results.partition { _1.route.domain == ANSWER_DOMAIN } + # allowed only one answer message + raise InvalidAnswersMessagesCountError.new("Get #{asnwers.size} on processing message with id=#{message_id}") if answers.size > 1 + + answer = answers.first + Concurrent::Promises.zip_futures(*sended_messages.map do |result| publish_result(result) end).then do |_successes| incoming.ack(answer: answer) end.rescue do |*errors| error = errors.compact.first @@ -201,9 +220,13 @@ # @return [Concurrent::Promises::ResolvableFuture] def publish_result(result) route = result.route logger.debug "Publish result to #{route} ..." publisher = publishers.find {|pub| pub.protocols.include?(route.scheme) } + if route.scheme.nil? || route.scheme == DEFAULT_PROTOCOL + logger.debug "Use default publisher for result with route=#{route}" + publisher = default_publisher + end raise "Not found publisher for scheme #{route.scheme}" if publisher.nil? # return Concurrent::Promises.resolvable_future publisher.publish(result) end