Update trigger abort behavior when running parallel actions
When the provider supports parallel actions and actions are being run in parallel, do not immediately kill the process on failure. Instead terminate the action thread and log the exit code. Once all running actions have completed, the process will then exit with the stored exit code.
This commit is contained in:
parent
d0115de80e
commit
88c675694a
|
@ -71,6 +71,10 @@ module Vagrant
|
|||
thread = Thread.new do
|
||||
Thread.current[:error] = nil
|
||||
|
||||
# Note that this thread is being used for running
|
||||
# a batch action
|
||||
Thread.current[:batch_parallel_action] = par
|
||||
|
||||
# Record our pid when we started in order to figure out if
|
||||
# we've forked...
|
||||
start_pid = Process.pid
|
||||
|
@ -160,6 +164,16 @@ module Vagrant
|
|||
if !errors.empty?
|
||||
raise Errors::BatchMultiError, message: errors.join("\n\n")
|
||||
end
|
||||
|
||||
# Check if any threads set an exit code and exit if found. If
|
||||
# multiple threads have exit code values set, the first encountered
|
||||
# will be the value used.
|
||||
threads.each do |thread|
|
||||
if thread[:exit_code]
|
||||
@logger.debug("Found exit code set within batch action thread. Exiting")
|
||||
Process.exit!(thread[:exit_code])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -300,8 +300,17 @@ module Vagrant
|
|||
#
|
||||
# @param [Integer] code Code to exit Vagrant on
|
||||
def trigger_abort(exit_code)
|
||||
@ui.warn(I18n.t("vagrant.trigger.abort"))
|
||||
Process.exit!(exit_code)
|
||||
if Thread.current[:batch_parallel_action]
|
||||
@ui.warn(I18n.t("vagrant.trigger.abort_threaded"))
|
||||
@logger.debug("Trigger abort within parallel batch action. " \
|
||||
"Setting exit code and terminating.")
|
||||
Thread.current[:exit_code] = exit_code
|
||||
Thread.current.terminate
|
||||
else
|
||||
@ui.warn(I18n.t("vagrant.trigger.abort"))
|
||||
@logger.debug("Trigger abort within non-parallel action, exiting directly")
|
||||
Process.exit!(exit_code)
|
||||
end
|
||||
end
|
||||
|
||||
# Calls the given ruby block for execution
|
||||
|
|
|
@ -297,6 +297,9 @@ en:
|
|||
Trigger configured to continue on error...
|
||||
abort: |-
|
||||
Vagrant has been configured to abort. Terminating now...
|
||||
abort_threaded: |-
|
||||
Vagrant has been configured to abort. Vagrant will terminate
|
||||
after remaining running actions have completed...
|
||||
start: |-
|
||||
Running %{type} triggers %{stage} %{action} ...
|
||||
fire_with_name: |-
|
||||
|
|
|
@ -63,5 +63,24 @@ describe Vagrant::BatchAction do
|
|||
subject.action(machine, "up")
|
||||
subject.run
|
||||
end
|
||||
|
||||
context "with provider supporting parallel actions" do
|
||||
let(:provider_options) { {parallel: true} }
|
||||
|
||||
it "should flag threads as being parallel actions" do
|
||||
parallel = nil
|
||||
subject.custom(machine) { |m| parallel = Thread.current[:batch_parallel_action] }
|
||||
subject.custom(machine) { |*_| }
|
||||
subject.run
|
||||
expect(parallel).to eq(true)
|
||||
end
|
||||
|
||||
it "should exit the process if exit_code has been set" do
|
||||
subject.custom(machine) { |m| Thread.current[:exit_code] = 1}
|
||||
subject.custom(machine) { |*_| }
|
||||
expect(Process).to receive(:exit!).with(1)
|
||||
subject.run
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -423,6 +423,37 @@ describe Vagrant::Plugin::V2::Trigger do
|
|||
expect(Process).to receive(:exit!).with(3)
|
||||
subject.send(:trigger_abort, 3)
|
||||
end
|
||||
|
||||
context "when running in parallel" do
|
||||
let(:thread) {
|
||||
@t ||= Thread.new do
|
||||
Thread.current[:batch_parallel_action] = true
|
||||
Thread.stop
|
||||
subject.send(:trigger_abort, exit_code)
|
||||
end
|
||||
}
|
||||
let(:exit_code) { 22 }
|
||||
|
||||
before do
|
||||
expect(Process).not_to receive(:exit!)
|
||||
sleep(0.1) until thread.stop?
|
||||
end
|
||||
|
||||
after { @t = nil }
|
||||
|
||||
it "should terminate the thread" do
|
||||
expect(thread).to receive(:terminate).and_call_original
|
||||
thread.wakeup
|
||||
thread.join(1) while thread.alive?
|
||||
end
|
||||
|
||||
it "should set the exit code into the thread data" do
|
||||
expect(thread).to receive(:terminate).and_call_original
|
||||
thread.wakeup
|
||||
thread.join(1) while thread.alive?
|
||||
expect(thread[:exit_code]).to eq(exit_code)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "#ruby" do
|
||||
|
|
Loading…
Reference in New Issue