183 lines
5.6 KiB
Ruby
183 lines
5.6 KiB
Ruby
# Copyright 2013 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
require 'raemon'
|
|
require 'net/http'
|
|
require 'bunny'
|
|
|
|
module Astute
|
|
module Server
|
|
|
|
class Worker
|
|
include Raemon::Worker
|
|
|
|
DELAY_SEC = 5
|
|
|
|
def start
|
|
super
|
|
start_heartbeat
|
|
Astute::Server::AsyncLogger.start_up(Astute.logger)
|
|
Astute.logger = Astute::Server::AsyncLogger
|
|
end
|
|
|
|
def stop
|
|
super
|
|
@connection.stop if defined?(@connection) && @connection.present?
|
|
@producer.stop if defined?(@producer) && @producer.present?
|
|
@server.stop if defined?(@server) && @server.present?
|
|
Astute::Server::AsyncLogger.shutdown
|
|
end
|
|
|
|
def run
|
|
Astute.logger.info "Worker initialization"
|
|
run_server
|
|
rescue Bunny::TCPConnectionFailed => e
|
|
Astute.logger.warn "TCP connection to AMQP failed: #{e.message}. "\
|
|
"Retry #{DELAY_SEC} sec later..."
|
|
sleep DELAY_SEC
|
|
retry
|
|
rescue Bunny::PossibleAuthenticationFailureError => e
|
|
Astute.logger.warn "If problem repeated more than 5 minutes, "\
|
|
"please check "\
|
|
"authentication parameters. #{e.message}. "\
|
|
"Retry #{DELAY_SEC} sec later..."
|
|
sleep DELAY_SEC
|
|
retry
|
|
rescue => e
|
|
Astute.logger.error "Exception during worker initialization:"\
|
|
" #{e.message}, trace: #{e.format_backtrace}"
|
|
Astute.logger.warn "Retry #{DELAY_SEC} sec later..."
|
|
sleep DELAY_SEC
|
|
retry
|
|
end
|
|
|
|
private
|
|
|
|
def start_heartbeat
|
|
@heartbeat ||= Thread.new do
|
|
sleep 30
|
|
heartbeat!
|
|
end
|
|
end
|
|
|
|
def run_server
|
|
@connection = Bunny.new(connection_options)
|
|
@connection.start
|
|
channels_and_exchanges = declare_channels_and_exchanges(@connection)
|
|
|
|
@producer = Astute::Server::Producer.new(
|
|
channels_and_exchanges[:report_exchange]
|
|
)
|
|
delegate = Astute::Server::Dispatcher.new(@producer)
|
|
@server = Astute::Server::Server.new(
|
|
channels_and_exchanges,
|
|
delegate,
|
|
@producer
|
|
)
|
|
|
|
@server.run
|
|
end
|
|
|
|
def declare_channels_and_exchanges(connection)
|
|
# WARN: Bunny::Channel are designed to assume they are
|
|
# not shared between threads.
|
|
channel = @connection.create_channel
|
|
exchange = channel.topic(
|
|
Astute.config.broker_exchange,
|
|
:durable => true
|
|
)
|
|
|
|
report_channel = @connection.create_channel
|
|
report_exchange = report_channel.topic(
|
|
Astute.config.broker_exchange,
|
|
:durable => true
|
|
)
|
|
|
|
service_channel = @connection.create_channel
|
|
service_channel.prefetch(0)
|
|
|
|
service_exchange = service_channel.fanout(
|
|
Astute.config.broker_service_exchange,
|
|
:auto_delete => true
|
|
)
|
|
|
|
return {
|
|
:exchange => exchange,
|
|
:service_exchange => service_exchange,
|
|
:channel => channel,
|
|
:service_channel => service_channel,
|
|
:report_channel => report_channel,
|
|
:report_exchange => report_exchange
|
|
}
|
|
rescue Bunny::PreconditionFailed => e
|
|
Astute.logger.warn "Try to remove problem exchanges and queues"
|
|
if connection.queue_exists? Astute.config.broker_queue
|
|
channel.queue_delete Astute.config.broker_queue
|
|
end
|
|
if connection.queue_exists? Astute.config.broker_publisher_queue
|
|
channel.queue_delete Astute.config.broker_publisher_queue
|
|
end
|
|
|
|
cleanup_rabbitmq_stuff
|
|
raise e
|
|
end
|
|
|
|
def connection_options
|
|
{
|
|
:host => Astute.config.broker_host,
|
|
:port => Astute.config.broker_port,
|
|
:user => Astute.config.broker_username,
|
|
:pass => Astute.config.broker_password,
|
|
:heartbeat => :server
|
|
}.reject{|k, v| v.nil? }
|
|
end
|
|
|
|
def cleanup_rabbitmq_stuff
|
|
Astute.logger.warn "Try to remove problem exchanges and queues"
|
|
|
|
|
|
[Astute.config.broker_exchange,
|
|
Astute.config.broker_service_exchange].each do |exchange|
|
|
rest_delete("/api/exchanges/%2F/#{exchange}")
|
|
end
|
|
end
|
|
|
|
def rest_delete(url)
|
|
http = Net::HTTP.new(
|
|
Astute.config.broker_host,
|
|
Astute.config.broker_rest_api_port
|
|
)
|
|
request = Net::HTTP::Delete.new(url)
|
|
request.basic_auth(
|
|
Astute.config.broker_username,
|
|
Astute.config.broker_password
|
|
)
|
|
|
|
response = http.request(request)
|
|
|
|
case response.code.to_i
|
|
when 204 then Astute.logger.debug "Successfully delete object at #{url}"
|
|
when 404 then
|
|
else
|
|
Astute.logger.error "Failed to perform delete request. Debug"\
|
|
" information: http code: #{response.code},"\
|
|
" message: #{response.message},"\
|
|
" body #{response.body}"
|
|
end
|
|
end
|
|
|
|
end # Worker
|
|
end #Server
|
|
end #Astute
|