I spent some time guiding a coworker through using Alembic for the first time with Socorro. I’ve been using Alembic for about three months now, and really liking it a lot. Setting things up initially was pretty simple, but explaining it to a coworker after I’d set everything up for myself proved slightly more difficult.
Terminology
Alembic calls each migration a revision. Revisions know what order to be run in based on what the previous revision number is.
Preparation: edit config and activate a virtualenv
Our environment was set up per the alembic tutorial for creating an environment. I ran: alembic init alembic
, and put an alembic.ini-dist
file into our project’s config/
directory. I also modified alembic/env.py
to include or model.
You’ll need to modify alembic.ini-dist
, and copy it to config/alembic.ini
to fit your environment – setting the connection string and the path to the alembic directory are the two most important settings. We have a script which creates databases from our models.py
called setupdb_app.py
. This script takes --database_name
as a command-line argument. My default for our project is to use breakpad
.
We use a virtualenv
called socorro-virtualenv
. The virtualenv is created automatically if you run make test
. If you’re creating a standalone virtualenv, you can do that with virtualenv socorro-virtualenv
. Activate this with . socorro-virtualenv/bin/activate
.
Creating a revision
- Create a fresh database to work from. For Socorro, the command is:
PYTHONPATH=. socorro/external/postgresql/setupdb_app.py --database_name=breakpad
- Edit
models.py
with the change to the schema - Run:
PYTHONPATH=. alembic -c config/alembic.ini revision -m 'your message about the migration'
. The output will include the name of the new file. - Edit that file as needed
alembic/versions/*.py
- Run:
PYTHONPATH=. alembic -c config/alembic.ini upgrade +1
If all goes well, your revision is ready! If something goes wrong, edit and try again. The revision will automatically rollback if there are any errors.
Production deployment
You’ll need to deploy an alembic.ini
on your production database system and probably a virtualenv
to support your python modules.
We deploy our virtualenvs with our application, so this step was pretty simple for everything except for alembic itself. The virtualenv put in full, static paths for the python binaries and had some dependencies that I haven’t figured out yet for actually running alembic. To get around this, I created a virualenv locally on the system for the postgres user. Having your postgres user run the migrations locally is a must for me because I need to access the filesystem to pull in new versions of user defined functions stashed in the directory my model lives in.
I just deploy a new release of our application code on the database server locally, and then I run alembic against the versions
directory that’s deployed.
FAQ
And here’s an FAQ for the common problems folks ran into:
OOPS I forgot to create a database before I created a revision!
To “fix” this, try:
- Create the database from scratch using your current
models.py
. - Run:
PYTHONPATH=. alembic -c config/alembic.ini downgrade -1
- Run:
PYTHONPATH=. alembic -c config/alembic.ini upgrade +1
Error message: “Only a single head supported so far.”
I’m using schemas, and alembic doesn’t recognize them when I try to use --autogenerate
.
See include_symbol. And be sure to add this to both the “offline” and “online” versions of the revision code in env.py
.
Error message: Target database is not up to date.
This means you’ve got a file in your versions
directory that contains one or more migrations that haven’t been applied to the current database. You can either apply them with alembic upgrade head
or have a look in that directory and remove the migration(s) that you don’t want.