class Drunker::Executor
Constants
- RETRY_LIMIT
Attributes
artifact[R]
client[R]
config[R]
logger[R]
project_name[R]
source[R]
Public Class Methods
new(source:, config:, logger:)
click to toggle source
# File lib/drunker/executor.rb, line 5 def initialize(source:, config:, logger:) @project_name = "drunker-executor-#{Time.now.to_i}" @source = source logger.info("Creating artifact...") @artifact = Drunker::Artifact.new(config: config, logger: logger) @config = config @client = Aws::CodeBuild::Client.new(config.aws_client_options) @logger = logger end
Public Instance Methods
run()
click to toggle source
# File lib/drunker/executor.rb, line 15 def run setup_project do builders = create_builders loop do start_builders builders restart_failed_builders builders ran, waiting = builders.partition(&:ran?) running, finished = ran.partition(&:running?) finished.select(&:failed?).each do |builder| builder.errors.each do |error| logger.warn("Build failed: #{builder.build_id}") logger.warn("\tphase_type: #{error[:phase_type]}") logger.warn("\tphase_status: #{error[:phase_status]}") logger.warn("\tstatus: #{error[:status]}") logger.warn("\tmessage: #{error[:message]}") end end if waiting.count.zero? && running.count.zero? logger.info("Build is completed!") break end logger.info("Waiting builders: #{finished.count}/#{builders.count}, queues: #{waiting.count}") sleep 5 builders.each(&:refresh) end artifact.layers # load artifact layers from S3 end artifact end
Private Instance Methods
create_builders()
click to toggle source
# File lib/drunker/executor.rb, line 104 def create_builders files_list = source.target_files.each_slice(source.target_files.count.quo(config.concurrency).ceil).to_a logger.info("Start parallel build: { files: #{source.target_files.count}, concurrency: #{config.concurrency}, real_concurrency: #{files_list.count} }") files_list.to_a.each_with_object([]) do |files, builders| builder = Builder.new(project_name: project_name, targets: files, artifact: artifact, config: config, logger: logger) builders << builder end end
restart_failed_builders(builders)
click to toggle source
# File lib/drunker/executor.rb, line 123 def restart_failed_builders(builders) builders.select(&:access_denied?).each do |builder| failed_id = builder.build_id if builder.retriable? build_id = builder.retry artifact.replace_build(before: failed_id ,after: build_id) end end end
setup_project() { || ... }
click to toggle source
# File lib/drunker/executor.rb, line 59 def setup_project logger.info("Creating IAM resources...") iam = IAM.new(source: source, artifact: artifact, config: config, logger: logger) retry_count = 0 logger.info("Creating project...") project_info = { name: project_name, source: source.to_h, artifacts: artifact.to_h, environment: { type: "LINUX_CONTAINER", image: config.image, compute_type: config.compute_type, }, service_role: iam.role.name, timeout_in_minutes: config.timeout, } project_info[:environment][:environment_variables] = config.environment_variables unless config.environment_variables.empty? begin client.create_project(project_info) logger.info("Created project: #{project_name}") # Sometimes `CodeBuild is not authorized to perform: sts:AssumeRole` error occurs... # We can solve this problem by retrying after a while. rescue Aws::CodeBuild::Errors::InvalidInputException if retry_count < RETRY_LIMIT retry_count += 1 sleep 5 logger.info("Retrying...") retry else raise end end yield unless config.debug? logger.info("Deleting IAM resources...") iam.delete client.delete_project(name: project_name) logger.info("Deleted project: #{project_name}") end end
start_builders(builders)
click to toggle source
# File lib/drunker/executor.rb, line 113 def start_builders(builders) builders.reject(&:ran?).each do |builder| build_id = builder.run artifact.set_build(build_id) end rescue Aws::CodeBuild::Errors::AccountLimitExceededException => exn logger.info("Maximum number of concurrent running builds has been reached. it will retry later...") logger.debug("Exception: #{exn.inspect}") end