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