From af6f10c64fc672e34f648c6ec912539e31e35c72 Mon Sep 17 00:00:00 2001 From: Kohei Suzuki Date: Tue, 3 Oct 2017 16:21:09 +0900 Subject: [PATCH] Build queue_url without database when maintenance mode is enabled Basically, we should use stored queue URL as the documentation[1] suggests. But when the Barbeque's database is temporarily unavailable due to scheduled maintenance, we have to build queue URL without the database. The maintenance mode is enabled by BARBEQUE_DATABASE_MAINTENANCE and AWS_ACCOUNT_ID variable. [1]: http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-queue-message-identifiers.html#sqs-general-identifiers --- app/models/barbeque/job_queue.rb | 23 ++++++++++++++++ .../barbeque/message_enqueuing_service.rb | 4 +-- spec/factories/job_queue.rb | 2 +- .../message_enqueuing_service_spec.rb | 26 ++++++++++++++++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/app/models/barbeque/job_queue.rb b/app/models/barbeque/job_queue.rb index 1a5c213..383992f 100644 --- a/app/models/barbeque/job_queue.rb +++ b/app/models/barbeque/job_queue.rb @@ -13,4 +13,27 @@ class Barbeque::JobQueue < Barbeque::ApplicationRecord def sqs_queue_name SQS_NAME_PREFIX + name end + + # Returns queue URL of given name. + # Basically, we should use stored queue URL as the documentation[1] suggests. + # But when the Barbeque's database is temporarily unavailable due to + # scheduled maintenance, we have to build queue URL without the database. The + # maintenance mode is enabled by BARBEQUE_DATABASE_MAINTENANCE and + # AWS_ACCOUNT_ID variable. + # [1]: http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-queue-message-identifiers.html#sqs-general-identifiers + # + # @param name [String] queue name in Barbeque + # @return [String] queue URL of SQS + def self.queue_url_from_name(name) + if database_maintenance_mode? + "https://sqs.#{ENV.fetch('AWS_REGION')}.amazonaws.com/#{ENV.fetch('AWS_ACCOUNT_ID')}/#{SQS_NAME_PREFIX}#{name}" + else + select(:queue_url).find_by!(name: name).queue_url + end + end + + def self.database_maintenance_mode? + ENV['BARBEQUE_DATABASE_MAINTENANCE'] == '1' && ENV['AWS_REGION'].present? && ENV['AWS_ACCOUNT_ID'].present? + end + private_class_method :database_maintenance_mode? end diff --git a/app/services/barbeque/message_enqueuing_service.rb b/app/services/barbeque/message_enqueuing_service.rb index 2cc5dc9..c4efdc2 100644 --- a/app/services/barbeque/message_enqueuing_service.rb +++ b/app/services/barbeque/message_enqueuing_service.rb @@ -20,9 +20,9 @@ def initialize(application:, job:, message:, queue: nil) # @return [String] message_id def run - queue = Barbeque::JobQueue.find_by!(name: @queue) + queue_url = Barbeque::JobQueue.queue_url_from_name(@queue) response = Barbeque::MessageEnqueuingService.sqs_client.send_message( - queue_url: queue.queue_url, + queue_url: queue_url, message_body: build_message.to_json, ) response.message_id diff --git a/spec/factories/job_queue.rb b/spec/factories/job_queue.rb index 6a61cdd..eae3f3b 100644 --- a/spec/factories/job_queue.rb +++ b/spec/factories/job_queue.rb @@ -1,7 +1,7 @@ FactoryGirl.define do factory :job_queue, class: Barbeque::JobQueue do sequence(:name) { |n| "queue-#{n}" } - sequence(:queue_url) { |n| "https://sqs.ap-northeast-1.amazonaws.com/123456789012/Barbeque-#{n}" } + queue_url { "https://sqs.ap-northeast-1.amazonaws.com/123456789012/Barbeque-#{name}" } description 'Default queue' end end diff --git a/spec/services/message_enqueuing_service_spec.rb b/spec/services/message_enqueuing_service_spec.rb index a26c617..f28f940 100644 --- a/spec/services/message_enqueuing_service_spec.rb +++ b/spec/services/message_enqueuing_service_spec.rb @@ -11,7 +11,7 @@ let(:send_message_result) { double('Aws::SQS::Types::SendMessageResult', message_id: message_id) } before do - allow(Aws::SQS::Client).to receive(:new).and_return(sqs_client) + allow(described_class).to receive(:sqs_client).and_return(sqs_client) end it 'enqueues a message whose type is JobExecution' do @@ -49,5 +49,29 @@ }.to raise_error(ActiveRecord::RecordNotFound) end end + + context 'when database is unavailable' do + around do |example| + env = ENV.to_h + ENV['BARBEQUE_DATABASE_MAINTENANCE'] = '1' + ENV['AWS_REGION'] = 'ap-northeast-1' + ENV['AWS_ACCOUNT_ID'] = '123456789012' + example.run + ENV.replace(env) + end + + it 'builds queue_url without database' do + expect(sqs_client).to receive(:send_message).with(hash_including(queue_url: job_queue.queue_url)).and_return(send_message_result) + expect(Barbeque::JobQueue).to_not receive(:connection) + + result = Barbeque::MessageEnqueuingService.new( + job: job, + queue: job_queue.name, + message: message, + application: application, + ).run + expect(result).to eq(message_id) + end + end end end