Search code examples
ruby-on-railsrubyrakerake-task

Why does this rake task run twice?


I have a main rake task setup_a_new_set_of_snippets.rake that I call, that then calls other tasks. So the main one looks like this:

load './lib/tasks/fetch_and_create_snippets.rake'
load './lib/tasks/generate_diffs_for_snippets.rake'
load './lib/tasks/cleanup_snippets_with_empty_diffs.rake'

desc "Setup a new set of Snippets"
task :setup_a_new_set_of_snippets, [:repo, :path, :entry_id, :framework_id, :method_name] => :environment do |task, args|
  repo = args[:repo]
  path = args[:path]
  entry_id = args[:entry_id]
  framework_id = args[:framework_id]
  method_name = args[:method_name]
  Rake::Task["fetch_and_create_snippets"].invoke(repo,path,entry_id,framework_id,method_name)
  Rake::Task["generate_diffs_for_snippets"].invoke
  Rake::Task["cleanup_snippets_with_empty_diffs"].invoke(framework_id)
end

For some reason, the fetch_and_create_snippets rake which is run like this: Rake::Task["fetch_and_create_snippets"].invoke(repo,path,entry_id,framework_id,method_name) seems to be run twice.

Here is that task - fetch_and_create_snippets.rake:

desc 'Fetch and Create Snippets from Github'

task :fetch_and_create_snippets, [:repo, :path, :entry_id, :framework_id, :method_name] => :environment do |task, args|
  repo = args[:repo]
  path = args[:path]
  entry_id = args[:entry_id]
  framework_id = args[:framework_id]
  method_name = args[:method_name]
  client = Octokit.client
  commits = GetCommits.new(repo, path).all
  commits_count = commits.count
  commits.each_with_index do |commit, index|
    content = client.contents(repo, path: path, ref: commit.sha)
    if Snippet.exists?(gh_sha: content.sha)
      puts "#{index}/#{commits_count} - EXISTS - #{commit.commit.author.email} - #{content.sha}".blue
    elsif commit.author.nil?
      puts "#{index}/#{commits_count} - NO AUTHOR - #{commit.commit.author.email} - #{content.sha}".magenta
    else
      create_snippet = CreateSnippet.new(repo, path, entry_id, framework_id, commit, method_name)
      if create_snippet
        puts "#{index}/#{commits_count} - #{commit.author.login} - #{commit.sha} SUCCESSFULLY CREATED".green
      else
        puts "#{index}/#{commits_count} - #{commit.author.login} - #{commit.sha} - NOT SUCCESSFULLY CREATED - #{create_snippet.errors}".red
      end
    end
  end
end

This is what the output to the console looks like:

First batch of successfully run events from the first run of fetch_and_create_snippets:

783/786 - dhh - ac3c8a54f83418b5cac4b093fc1bae29f59f3a1f SUCCESSFULLY CREATED
Snippet ID: 2974 SUCCESSFULLY SANITIZED
784/786 - dhh - 7022dd9c05064ef914f8836fb5e8b2d2ee3c02ed SUCCESSFULLY CREATED
Snippet ID: 2975 SUCCESSFULLY SANITIZED
785/786 - dhh - db045dbbf60b53dbe013ef25554fd013baf88134 SUCCESSFULLY CREATED

Then it re-runs it and shows the EXISTS output, which only outputs once the Snippet exists.

0/786 - EXISTS - acme@test.com - c91b5d3fe3d263963eb3f9ef2ec0dc0074951064
1/786 - EXISTS - acme@test.com - 3729e22e6423348aa9282cd17b49c09793ca3a6f
2/786 - EXISTS - acme@test.com - ec9b073c185dcef26bd3293ac124fee8285de103
3/786 - EXISTS - acme@test.com - 5a973fa8019962133449c073c4e8b5cf2ce8fb36
4/786 - EXISTS - acme@test.com - fe440fccc7398d2cd0b4f04f700c62cc76ba2b0a
5/786 - EXISTS - acme@test.com - 2fbecb7d0447b70b30b71addfbc97608690b4106
6/786 - EXISTS - acme@test.com - 77d17fc9757bcbbc63267c2e408b4dbe8ab5d930
7/786 - EXISTS - acme@test.com - ef35d80523fd066ae1d836658ef840dd0da93849
8/786 - EXISTS - acme@test.com - e13fe33b857c7f608590bf80030f8c837a15faea
9/786 - EXISTS - acme@test.com - 03c8b4c97be4ffaf1f84daf657915d8953219476

And that runs through the same batch it did the first time.

What could be causing this double run?


Solution

  • Try to remove load methods.
    In Rails project all *.rake files inside of lib/tasks directory are automatically loaded. So all those tasks would be available without extra load.

    In your Rakefile you can see initially generated comment like

    Add your own tasks in files placed in lib/tasks ending in .rake, for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

    I have created simple .rake files.

    # lib/tasks/foo.rake

    desc 'foo task'
    task :foo do
      puts 'call foo task'
    end
    

    # lib/tasks/bar.rake

    desc 'bar task'
    task :bar do
      puts 'call bar task'
      Rake::Task['foo'].invoke
    end
    

    It works fine like this. The output is

    # => call bar task
    # => call foo task
    

    But if I add load in bar.rake

    load './lib/tasks/foo.rake'
    desc 'bar task'
    task :bar do
      puts 'call bar task'
      Rake::Task['foo'].invoke
    end
    

    foo task will be called twice.

    # => call bar task
    # => call foo task
    # => call foo task