Django Upgrade Checklist

NOTE: This document is a living document intended to aid developers working on Django upgrades. Feel free to contribute additional knowledge.


The Django framework is the single most important dependency of our web services. While some upgrades—bug fixes—are trivial, major upgrades (e.g. 1.8 to 1.9) can be pretty significant. Below are the best practices for upgrading Django. Some are "common sense". Others we have, unfortunately, learned the hard way after bringing down production.

Preflight

Before you upgrade Django, you need to clean the existing code and dependencies.


  1. Check dependencies for compatibility. Sometimes dependencies maintained by third-parties (or even edX!) are not compatible with updated versions of Django. Determine which are not, and create a list of those dependencies. At a minimum, reach out to the maintainers requesting if/when an update will be released. Depending on the the timeline of the upgrade of the dependency, and our own urgency to start using the new version of Django, we have a few options:
    1. Work with the maintainers to update/release the library.
    2. Deploy from a fork until the main repository is updated.
    3. Replace the library with an alternative.
  2. Resolve all deprecation warnings that are logged for the current version of Django. This should ensure that features removed in the future version of Django are no longer used. Under no circumstances should you resolve deprecation issues by disabling deprecation warnings!
  3. Read the Django release notes...twice! Pay special attention to features that have been removed and/or deprecated.
  4. Release these changes independently of the actual Django upgrade to limit the scope of any potential issues.

Inflight

Once deprecation and dependency issues have been resolved, the actual upgrade should be pretty straightforward. In some cases you may only need to update the requirements and generate a few migrations!

  1. Read the release notes again.
  2. Upgrade Django in the appropriate requirements file.
  3. Run makemigrations to generate any new migrations for Django-maintained tables (e.g. group/user tables).
    1. If there are migrations that affect tables with a large number of rows (e.g. user tables), talk to DevOps to determine a release plan! Depending on the change, we may opt to fake the migration in production.
    2. If you do not know how many rows are in an affected table, talk to DevOps to get help finding this information! (Admitting you don't know before the release is very much preferred to doing so once the service goes down!)
  4. Loadtest the new changes. Ideally performance should improve or remain the same. More importantly, however, we want to execute the code in an environment with production-like data scale.
  5. Update the Open edX release notes at Open edX Release Planning. Open source maintainers will need to run similar, if not the same, processes we run to upgrade. Update the release notes informing them of the upgrade and anything to be weary of (e.g. migrations affecting large tables).
  6. Release the Django upgrade by itself. If it breaks, we know exactly what to revert to fix it.

Post-flight

Just because the build pipeline is green doesn't mean you're done!

  1. Monitor the service for a few hours after release. Look out for decreased performance/increased load times. Look out for Splunk alerts. If you need help with this, chat with your friends in DevOps.
  2. Update this document to improve it for those doing future upgrades.