Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Do not belittle rake tasks

November 06, 2018

Do not belittle rake tasks


November 06, 2018

More Decks by mbie

Other Decks in Programming


  1. What is a rake task? • Just a script to

    run at any time in a console • Common Rails tasks: ◦ rake db:reset, rake db:create, rake db:migrate ◦ rake -T ◦ rake routes • Custom task: desc 'Rake task description' task :name_of_task do # Your code goes here end
  2. When we use custom rake tasks? • Script automation •

    Data cleanup • Long database migration
  3. Why is it important to write a good custom rake

    task? • Usually it’s production code • Readability • Maintainability • Testing • Transparency
  4. My list of the things to consider • Size of

    .rake file • Idempotency • Tracking progress • Logging the work • Isolated structure • Testing • The performance
  5. Ideal .rake file namespace :mailchimp desc 'Import users from Mailchimp'

    task import_users: :environment do Mailchimp::ImportUsers.call end end
  6. Keep .rake file as small as possible namespace :mailchimp desc

    'Import users from Mailchimp' task :import_users do puts 'Importing users from Mailchimp' result = Mailchimp::ImportUsers.call puts "Successfully imported #{result} users!" end end
  7. Idempotency • It’s important on cleanups and migrations • Can

    be easily fulfilled with: ◦ a good query ◦ modifying the input file ◦ omitting already created data
  8. Tracking progress • The task executor needs to know the

    current status of the task • Show anything ◦ from dots ◦ to printing a line for each processed item • Or use a gem ProgressBar:
  9. ProgressBar gem namespace :cleanup desc 'Cleanup bad fees' task :fix_bad_fees

    do query = Cleanup::FixBadFees::Query.call progress_bar = ProgressBar.create( title: 'Fixing bad fees by adding a discount', total: query.count ) # ... end end namespace :cleanup desc 'Cleanup bad fees' task :fix_bad_fees do # ... result = Cleanup::FixBadFees::Task.call(query: query) do progress_bar.increment end puts "Successfully fixed #{result} fees!" end end
  10. ProgressBar gem class Cleanup::FixBadFees::Task def self.call(*args, &block) new.self(*args, &block) end

    def call(query:) query.find_each do # Fix bad fees yield if block_given? end end end
  11. Logging • Who performed the task? When? Why? • Log

    the action ◦ Notes ◦ Audit trail ◦ History events • Log the task’s execution • Include the executor ◦ TASK_EXECUTOR=jon.snow@westeros rake kill_undead
  12. Isolated structure • .rake files usually in /lib/tasks • The

    rest in /app/tasks • Each task in a separated module
  13. Testing custom rake tasks • Automated tests class for each

    PORO class used in a rake task • No automated tests for .rake file, rely on manual testing • Don’t be lazy
  14. Performance • Predict the scale at the very beginning •

    Define bottlenecks ◦ Reading from large file or from multiple database tables ◦ Calling external services ◦ Saving many rows to the database • Use database close to production (locally, staging)
  15. Summary • Rake task are a part of our application

    • Bad task may cause a lot of damage • With a little of effort we can do it right