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

Do not belittle rake tasks

Avatar for mbie mbie
November 06, 2018

Do not belittle rake tasks

Avatar for mbie

mbie

November 06, 2018
Tweet

More Decks by mbie

Other Decks in Programming

Transcript

  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