Running ./manage.py migrate during Heroku deployment - django

I am working on a Django app, and I would like my Database migrations to be run when deploying on Heroku.
So far we have simply put the following command in the Procfile:
python manage.py migrate
When deploying the migrations are indeed run, but they seem to be run once for each dyno (and we use several dynos). As a consequence, data migrations (as opposed to pure schema migrations) are run several times, and data is duplicated.
Running heroku run python manage.py migrate after the deployment is not satisfactory since we want the database to be in sync with the code at all times.
What is the correct way to do this in Heroku?
Thanks.

This is my Procfile and it is working exactly as you describe:
release: python manage.py migrate
web: run-program waitress-serve --port=$PORT settings.wsgi:application
See Heroku docs on defining a release process:
https://devcenter.heroku.com/articles/release-phase#defining-a-release-command
The release command is run immediately after a release is created, but before the release is deployed to the app’s dyno formation. That means it will be run after an event that creates a new release:
An app build
A pipeline promotion
A config var change
A rollback
A release via the platform API
The app dynos will not boot on a new release until the release command finishes successfully.
If the release command exits with a non-zero exit status, or if it’s shut down by the dyno manager, the release will be discarded and will not be deployed to the app’s formation.
Be aware, however, this feature is still in beta.
Update:
When you have migrations that remove models and content types, Django requires a confirmation in the console
The following content types are stale and need to be deleted:
...
Any objects related to these content types by a foreign key will also be deleted. Are you sure you want to delete these content types? If you're unsure, answer 'no'. Type 'yes' to continue, or 'no' to cancel:
The migrate command in your Procfile does not respond and the release command fails. In this scenario, remove the migrate line, push live, run the migrate command manually, then add it back for future deploys.

The migrate does automatically runs on Heroku, but for now you can safely do it once your dyno is deployed with heroku run python manage.py migrate.
If production, you can put your app in maintenance first with heroku maintenance:on --app=<app name here>

Setup your Procfile like in the docs
release: python manage.py migrate
web: gunicorn myproject.wsgi --log-file -
documented at https://devcenter.heroku.com/articles/release-phase#specifying-release-phase-tasks

You can create a file bin/post_compile which will run bash commands after the build.
Note that it is still considered experimental.
Read here for more buildpack info.
See here for an example
Alternatively, Heroku is working on a new Releases feature, which aims to simplify and solve this process. (Currently in Beta).
Good luck!

Related

Django migrate works but doesn't reflect on live site

I made some updates to a project: add 1 admin model, add 1 template
I'm using wagtail. I pulled the updates to my server, ran migrations, got success. I restart nginx and gunicorn, I even rebooted the server.
When I go to the wagtail admin, my adminmodel is missing (it exists locally). when I go to create a new page, my template is available, but when I select it I get taken to a wagtail 404 page.
Ubuntu 20.04
ngnix
gunicorn
django/wagtail
digital ocean vpc
digital ocean postgres database cluster
The site works like normal, only a template is available I can't select, and the Model, that migrated, isn't available and isn't showing up in admin. my local version is working perfectly, with no differences. it seems like the server is both updating and not updating. I don't get it. running makemigrations or migrate returns no changes. even when running on the specific app. Do I need to do something to rebot the database?
Listen it looks like caching issue with Nginx. Try clearing the cache.
I have 2 settings files: dev.py, production.py
dev.py is connected to a sqlite3 db and production is connected to the digitalocean postgres cluster.
python manage.py automatically uses dev.py (at least in my setup) so my migrations were working, but they were targeting an old copy of the sqlite.db I had on the server, or perhaps created one as it does when one doesn't exist. Either way, the live site runs on the production.py settings and this is why the changes were being made but not reflecting.
The correct way to run migrations when you have a production.py file is similar to:
python manage.py migrate --settings=<settings app>.<settings folder>.production
I'm also going to add that I found that you need to collectstatic each time you update your css stylesheet. that is a little tedious, and maybe I am missing an automation step, but considering that is the case, just to be safe, I run like this:
python manage.py collectstatic --settings=<settings app>.<settings folder>.production
It doesn't cause any issues and it works, so I use the --settings flag to be safe.
git pull
python manage.py migrate --settings=app.settings.production
python manage.py collectstatic --settings=app.settings.production
sudo systemctl restart ngix
sudo systemctl restart gunicorn
I don't know that restarting ngix is necessary except it solved something with my static files updating I believe.

Django migration command hanging on Heroku even without actual new migration

We are running our stack on Heroku. We are using Django 2.2 with a Postgres 11 DB. Our build pipeline (Github Actions) pushes to Heroku (git push https://git.heroku.com...) and immediately afterwards runs the migrations (heroku run python manage.py migrate --app heroku-app-name). All of that was working with a Postgres 9.6 database and is still working in our staging environment (Postgres 11). Now with production being on Postgres 11, the django migrate command is just stuck and doesn't produce any output, even so there are no actual migrations to apply.
The only differences between our production setup and our staging setup are a follower/slave in production attached to the master DB and "production workload".
In order to fix that deployment I have to run a
heroku pg:killall -a heroku-app-name
heroku restart -a heroku-app-name
At this point the migrations task in the build pipeline fails.
and afterwards migrations can be applied manually without problems:
heroku run python manage.py migrate --app heroku-app-name
So for some reason the migrations command is "waiting" for something, some database lock or whatever, yet I cannot put my finger on it. Especially odd for me is the fact that its also stuck where no migrations are to applied. Why would it be stuck there?
We found the solution. There are actually three things coming together.
We trigger a DB backup before running any migrations. We only do so in Production and not on staging, which was the reason why our staging environment had no issues while production had.
A DB migration (even so it looks like there is nothing to apply) is actually running some commands (besides regular SELECT, UPDATE, INSERTS). E.g. in our case there was a CREATE EXTENSION ... IF NOT EXISTS always executed at the beginning.
While it was possible with Postgres 9.6 to have a backup job running in parallel (I don't know what heroku is using under the hood, yet I assume a noraml pg_dump) the backup job on Postgres 11 (and others?) has now a more exclusiv lock on some operations. I assume that that a CREATE EXTENSION ... IF NOT EXISTS (even so the extension already exists) cannot be executed while having a backup job running in parallel.
(I am sure there are some Postgres internas missing to explain this more correctly)
As a result of these three things, the DB blocks the migrate operation, waiting for the backup job to finish. I have moved the daily backup job to a different time and reconfigured our pipeline to wait for the "pre-deploy"-backup to finish first.

How to run Django migrations in Google App Engine Flexible deployment step?

I have a Django app up and running in Google App Engine flexible. I know how to run migrations using the cloud proxy or by setting the DATABASES value but I would like to automate running migrations by doing it in the deployment step. However, there does not seem to be a way to run a custom script before or after the deployment.
The only way I've come up with is by doing it in the entrypoint command which you can set in the app.yaml:
entrypoint: bash -c 'python3 manage.py migrate --noinput && gunicorn -b :$PORT app.wsgi'
This feels a lot like doing it wrong. A lot of Googling didn't provide a better answer.
Defining the python3 manage.py migrate command in your app.yaml file will make it run every time a new instance is spawned and set up to serve traffic. Although technically this may not be an issue (no migration will happen if database schema hasn't changed) this isn't the right place to declare it.
You'd want this command to run once on every new version code push. This fits perfectly in a CI/CD approach. There are several tutorials on the Google Cloud online documentation using Bitbucket Pipelines or Travis CI for example but you can use many other CI/CD solutions.

What to do to run makemigrations/migrate on heroku when deploying changed models from github?

I have deployed app from github repository to the heroku account of my customer as collaborator but this time I had to add some new models.
However I realized that when I deploy my changes from github heroku does not run makemigrations and migrate.
I I read some answers on stackoverflow and understood this is how it is supposed to be.
However my question is what should I do ? What is the best practise to deploy change models to heroku app. (I assume it is not deleting and recreating my app again since customer already has data there.)
(I am able to run makemigrations and migrate from the bash manually but when I have 30+ deployments it's a pain)
Check out the new feature on Heroku called "Release Phase": https://devcenter.heroku.com/articles/release-phase It will allow you to run migrations during the deployment. Just add whatever command you want to your Procfile, like this:
web: your_web_command
release: python manage.py migrate
The release command will run after your app is done building, and before it's launched.

Running migrations when deploying django app to heroku with codeship

I'm trying to set up a continous integration pipeline for my python 3.5.1 / django 1.9.7 project.
The project is running fine on heroku, and the codeship deployment pipeline for heroku works well as long as my database is unchanged.
If I want to run migrations, I have to do so manually by entering heroku run python manage.py migrate on my computer which I would like to avoid.
I added a "Custom Script" in my codeship deployment pipeline after the "heroku"-pipeline containing heroku run python manage.py migrate, but when coedship attempts to execute it, it fails with the
Cannot run more than 1 Free size dynos.
message. I assume this is because the server is already up and running and I don't have more worker processes available? (please correct me if I'm wrong)
EDIT: This is where I was wrong - I had an additional process running (see answer)
Is there any way to include the database migration step in the heroku deployment pipeline? Or did I do something wrong?
Ifound the answer here: Heroku: Cannot run more than 1 Free size dynos
My assumption about theweb server beeing the blocking dyno was wrong, I had a zombie process (createsuperuser) running I did not know about.
I used heroku ps to show all running prcesses. Output was:
=== web (Free): gunicorn my_app.wsgi --log-file - (1)
web.1: idle 2016/06/07 17:09:06 +0200 (~ 13h ago)
=== run: one-off processes (1)
run.7012 (Free): up 2016/06/07 15:19:13 +0200 (~ 15h ago): python manage.py createsuperuser
I killed the process by typing
heroku ps:stop run.7012
and afterwards my migration via codeship custom script worked as expected.