fuel-astute/lib/astute/server/worker.rb

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