Add strategy for DockerContainerPool

In order to provide an alternative to Poseidon, a strategy for the
DockerContainerPool is added that is used by the runner model.

Co-authored-by: Sebastian Serth <Sebastian.Serth@hpi.de>
This commit is contained in:
Felix Auringer
2021-06-10 16:17:02 +02:00
committed by Sebastian Serth
parent 1d3f0d7ad8
commit 704407b9fc
12 changed files with 282 additions and 69 deletions

View File

@@ -137,7 +137,7 @@ class SubmissionsController < ApplicationController
@output = +''
socket.on :output do |data|
Rails.logger.info("#{Time.zone.now.getutc}: Container sending: #{data}")
Rails.logger.info("#{Time.zone.now.getutc}: Container sending: #{data.inspect}")
@output << data if @output.size + data.size <= max_output_buffer_size
end
@@ -150,10 +150,6 @@ class SubmissionsController < ApplicationController
end
socket.on :exit do |exit_code|
# As this is sometimes called before the timeout is handled, we must not close the
# socket to the user here. The socket will be closed after handling the timeout.
next if exit_code == Runner::Connection::TIMEOUT_EXIT_STATUS
EventMachine.stop_event_loop
if @output.empty?
tubesock.send_data JSON.dump({cmd: :write, stream: :stdout, data: "#{t('exercises.implement.no_output', timestamp: l(Time.zone.now, format: :short))}\n"})

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'forwardable'
class Runner < ApplicationRecord
belongs_to :execution_environment
belongs_to :user, polymorphic: true
@@ -13,7 +11,6 @@ class Runner < ApplicationRecord
STRATEGY_NAME = CodeOcean::Config.new(:code_ocean).read[:runner_management][:strategy]
UNUSED_EXPIRATION_TIME = CodeOcean::Config.new(:code_ocean).read[:runner_management][:unused_runner_expiration_time].seconds
BASE_URL = CodeOcean::Config.new(:code_ocean).read[:runner_management][:url]
DELEGATED_STRATEGY_METHODS = %i[destroy_at_management attach_to_execution copy_files].freeze
attr_accessor :strategy
@@ -35,14 +32,20 @@ class Runner < ApplicationRecord
runner
end
DELEGATED_STRATEGY_METHODS.each do |method|
define_method(method) do |*args, &block|
@strategy.send(method, *args, &block)
rescue Runner::Error::RunnerNotFound
request_new_id
save
@strategy.send(method, *args, &block)
end
def copy_files(files)
@strategy.copy_files(files)
rescue Runner::Error::RunnerNotFound
request_new_id
save
@strategy.copy_files(files)
end
def attach_to_execution(command, &block)
@strategy.attach_to_execution(command, &block)
end
def destroy_at_management
@strategy.destroy_at_management
end
private
@@ -53,17 +56,19 @@ class Runner < ApplicationRecord
def request_new_id
strategy_class = self.class.strategy_class
self.runner_id = strategy_class.request_from_management(execution_environment)
@strategy = strategy_class.new(runner_id, execution_environment)
rescue Runner::Error::EnvironmentNotFound
if strategy_class.sync_environment(execution_environment)
raise Runner::Error::EnvironmentNotFound.new(
"The execution environment with id #{execution_environment.id} was not found and was successfully synced with the runner management"
)
else
raise Runner::Error::EnvironmentNotFound.new(
"The execution environment with id #{execution_environment.id} was not found and could not be synced with the runner management"
)
begin
self.runner_id = strategy_class.request_from_management(execution_environment)
@strategy = strategy_class.new(runner_id, execution_environment)
rescue Runner::Error::EnvironmentNotFound
if strategy_class.sync_environment(execution_environment)
raise Runner::Error::EnvironmentNotFound.new(
"The execution environment with id #{execution_environment.id} was not found and was successfully synced with the runner management"
)
else
raise Runner::Error::EnvironmentNotFound.new(
"The execution environment with id #{execution_environment.id} was not found and could not be synced with the runner management"
)
end
end
end
end

View File

@@ -184,18 +184,10 @@ class Submission < ApplicationRecord
private
def copy_files_to(runner)
files = {}
collect_files.each do |file|
files[file.name_with_extension] = file.content
end
runner.copy_files(files)
end
def prepared_runner
request_time = Time.zone.now
runner = Runner.for(user, exercise)
copy_files_to runner
runner.copy_files(collect_files)
waiting_duration = Time.zone.now - request_time
yield(runner, waiting_duration)
end
@@ -270,7 +262,7 @@ class Submission < ApplicationRecord
update(score: score)
if normalized_score.to_d == 1.0.to_d
Thread.new do
RequestForComment.find_each(exercise_id: exercise_id, user_id: user_id, user_type: user_type) do |rfc|
RequestForComment.where(exercise_id: exercise_id, user_id: user_id, user_type: user_type).find_each do |rfc|
rfc.full_score_reached = true
rfc.save
end