Skip to content

Commit

Permalink
Do not run tasks when their prerequisites fail
Browse files Browse the repository at this point in the history
If tasks A and B both depend on C, they race to grab the invocation
lock on C. If A wins, it sets @already_invoked and executes C while
holding the lock. When C completes, A releases the lock, B acquires it
and immediately returns since C is @already_invoked. Unfortunately,
this does not distinguish failed execution of C. Instead, if executing
C raises an exception for A, we want to raise the same exception in B
so it is aborted.
  • Loading branch information
ptarjan committed Jun 22, 2016
1 parent b63f7d3 commit 3a1b5bc
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 0 deletions.
36 changes: 36 additions & 0 deletions lib/rake/multi_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,42 @@ module Rake
# parallel using Ruby threads.
#
class MultiTask < Task

# Same as invoke, but explicitly pass a call chain to detect
# circular dependencies. This is largely copied from Rake::Task
# but has been updated such that if multiple tasks depend on this
# one in parallel, they will all fail if the first execution of
# this task fails.
def invoke_with_call_chain(task_args, invocation_chain)
new_chain = Rake::InvocationChain.append(self, invocation_chain)
@lock.synchronize do
begin
if @already_invoked
if @invocation_exception
if application.options.trace
application.trace "** Previous invocation of #{name} failed #{format_trace_flags}"
end
raise @invocation_exception
else
return
end
end

if application.options.trace
application.trace "** Invoke #{name} #{format_trace_flags}"
end
@already_invoked = true

invoke_prerequisites(task_args, new_chain)
execute(task_args) if needed?
rescue Exception => ex
add_chain_to(ex, new_chain)
@invocation_exception = ex
raise
end
end
end

private
def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
invoke_prerequisites_concurrently(task_args, invocation_chain)
Expand Down
21 changes: 21 additions & 0 deletions test/test_rake_multi_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,25 @@ def test_multitasks_with_parameters
assert @runs[0] == "b"
assert @runs[1] == "bmt"
end

def test_cross_thread_prerequisite_failures
failed = false

multitask :fail_once do
fail_now = !failed
failed = true
raise 'failing once' if fail_now
end

task a: :fail_once
task b: :fail_once

assert_raises RuntimeError do
Rake::Task[:a].invoke
end

assert_raises RuntimeError do
Rake::Task[:b].invoke
end
end
end

0 comments on commit 3a1b5bc

Please sign in to comment.