Does invoking multiple tasks from a parent rake lo

2019-08-01 05:34发布

问题:

If I have one rake which invokes multiple other rakes.

Once I initiate the parent rake

rake myapp:main

Then invokes done within the rake would load environment for each task or its just one time activity done while running rake myapp:main ?

namespace :myapp do
  desc "Main Run"
  task :main => :environment do
    Rake::Task['myapp:task1'].invoke
    Rake::Task['myapp:task2'].invoke
  end

  task :task1 => :environment do
    # Does the first task
  end

  task :task2 => :environment do
    # Does the second task
  end
end

回答1:

Adding details to @Shadwell's answer..

The => :environment is specifying that the :environment task (defined by rails) is a dependency of your tasks and must be invoked before your tasks are.

You can see :environment task's definition here

https://github.com/rails/rails/blob/d70ba48c4dd6b57d8f38612ea95a3842337c1419/railties/lib/rails/application.rb#L428-432

Rake keeps track of which tasks have invoked though and when it reaches a dependency that has already been invoked it knows it can skip it.

https://github.com/jimweirich/rake/blob/5e59bccecaf480d1de565ab34fd15e54ff667660/lib/rake/task.rb#L195-204

# Invoke all the prerequisites of a task.
def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
  if application.options.always_multitask
    invoke_prerequisites_concurrently(task_args, invocation_chain)
  else
    prerequisite_tasks.each { |p|
      prereq_args = task_args.new_scope(p.arg_names)
      p.invoke_with_call_chain(prereq_args, invocation_chain)
    }
  end
end

Rake maintains an intance variable @already_invoked to know if a task has already been called. The same can be seen in the below method

https://github.com/jimweirich/rake/blob/5e59bccecaf480d1de565ab34fd15e54ff667660/lib/rake/task.rb#L170-184

def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
  new_chain = InvocationChain.append(self, invocation_chain)
  @lock.synchronize do
    if application.options.trace
      application.trace "** Invoke #{name} #{format_trace_flags}"
    end
    return if @already_invoked
    @already_invoked = true
    invoke_prerequisites(task_args, new_chain)
    execute(task_args) if needed?
  end
rescue Exception => ex
  add_chain_to(ex, new_chain)
  raise ex
end


回答2:

The environment would only be set up once.

The => :environment is specifying that the :environment task (defined by rails) is a dependency of your tasks and must be invoked before your tasks are. Rake keeps track of which tasks have invoked though and when it reaches a dependency that has already been invoked it knows it can skip it.

(Aside: this can cause problems if you actually want the dependency to be invoked multiple times)

You could also define your main task using dependencies:

task :main => [:task1, :task2] do
  # Blank
end

When you run rake myapp:main it will look at the dependencies and invoke task1 and then task2. Because task1 has a dependency environment it will invoke that first too. It'll skip the environment dependency on task2 though.



回答3:

Answer is NO, Environment is not loaded when executing another Rake task from the parent Task. Simple explanation for this is the code below :

namespace :myapp do
  desc "Main Run"
  task :main => :environment do
    puts "Start Time : #{Time.now.to_i}"
    Rake::Task['myapp:task1'].invoke
    puts "End Time1 : #{Time.now.to_i}"
    Rake::Task['myapp:task2'].invoke
    puts "End Time2 : #{Time.now.to_i}"
  end

  task :task1 => :environment do
    # Does the first task
    puts "Executing..1"
  end

  task :task2 => :environment do
    # Does the second task
    puts "Executing..2"
  end
end

But it is not a good practice to do the two or multiple rake tasks. If you want to achieve the same thing, you can modularize the code, and create two functions and call the function to achieve the same result.