When I am deploying a rails application, there are sometimes one off tasks that I need done at release time, but not before. I’ve handled such tasks in the past by:
- adding a calendar entry (if I know when the release is happening)
- add a task or a story for the release and capture the tasks there
- writing a ‘release checklist’ document that I have to remember to check on release.
Depending on release frequency, application complexity and team size, the checklist may be small or it may have many tasks on it. Some tasks on a checklist can include:
- sending a communication (an email or slack message) to the team detailing released features
- restarting an external service to pick up configuration or code changes
- notifying a customer that a bug they reported has been fixed
- kicking off an external process via an API call now that a required dependency has been released
What these all have in common is that they:
- are not regular occurrences; they don’t happen every deploy
- are affecting entities (users or software) beyond code and database
- may or may not require human interaction
after_party is a gem helps with these tasks. This gem is similar in functionality to database migrations because each after_party
task is run once per environment (this is done by checkpointing the task timestamp in the database). However, after_party
tasks are arbitrary rake tasks, rather than the database manipulation DSL of migrations.
You add this call to your deployment scripts (the example is for heroku, feel free to replace heroku run with bundle exec):
heroku run rake after_party:run --app appname
This rake task will will run every time, but if an after_party
task has already been run and successfully recorded in the database, it will not be run again.
You can generate these tasks files: rails generate after_party:task my_task --description="desc"
Here’s what an after_party
task looks like:
namespace :after_party do desc 'Deployment task: notify customer about bug fix' task notify_issue_111: :environment do puts "Running deploy task 'notify_issue_111'" TfcAdminNotesMailer.send_release_update_notification("customer X", "issue 111").deliver_now AfterParty::TaskRecord.create version: '20180113164945' end # task :notify_issue_111 end # namespace :after_party
This particular task sends a release update notification email to the customer service user reminding them that we should notify customer X that issue #111 has been resolved. I couldn’t figure out how to make a rake task send email directly, hence the ActionMailer. In general you will want to push all of your logic from the rake task to POROs or other testable objects.
I could have sent the message directly to the customer rather than to customer service. However, I was worried that if a rollback happened, the customer might be informed incorrectly about the state of the application. I also thought it’d be a nice touchpoint, since issues are typically reported to customer service initially. The big win is that ten of these can be added over a period of weeks, and I could have gone on vacation during the release, and the customer update reminders would still be sent.
All is not puppies and rainbows, however. This gem doesn’t appear to be maintained. The last release was over two years ago, though there are forks that have been updated more recently. It works fine with my rails4 app. The main alternative that I’m aware of is hijacking a database migration and calling a rake task or ruby code in the ‘up’ migration clause. That seems non intuitive to me. I wouldn’t expect a database migration to touch anything outside of, well, the database.
Another thing to be aware of is that there is no rollback/roll forward functionality with after_party
. Once a task is run, it won’t get run again (unless you run the rake task manually or modify the task_records database table).
This gem will help you automate one off deployment tasks, and I hope you enjoy it.
Pingback: One hundred days of blogging every day | Dan Moore!