-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DM-42384: Add support for database migrations with Alembic #959
Conversation
4b86596
to
ffb6faf
Compare
This is the first time that I've used Alembic, and there were some non-obvious aspects to how to generate migrations and how to use an async database engine, so this seemed worth a code review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. I think it overall matches up with my experience using Alembic with LTD Keeper.
Big picture, I do wonder about running alembic on app startup, especially in Kubernetes. In LTD Keeper I always ran the migrations from a specific Kubernetes Job before deploying the new codebase. My thinking was coloured by this article: https://pythonspeed.com/articles/schema-migrations-server-startup/
In practice it might be totally fine always running alembic, but I wanted to bring this up.
Yeah, this was bothering me too and is a really good point. One of the things that's sort of entangled with this is that currently we run I feel like the right way to do this is to probably add a Helm chart parameter that says whether to automatically run schema updates (similar to the one for JupyterHub) and, if it is enabled, do a schema upgrade (and I'll add this to my to-do list and in the meantime I'll drop the automatic Alembic run, and will do this update manually if I don't get around to the more complicated thing before I am ready to push out this release. |
Add a new oidc token type as an initial migration, which is not yet used but will be used in a subsequent change. Use an async engine for Alembic, since that avoids needing to also install psycopg2 alongside asyncpg only for Alembic to use it. Since Alembic only sort-of supports async via asyncio.run, this requires moving the body of gafaelfawr init into a separate coroutine and running that with asyncio.run so that Alembic can be run outside of the running async loop. The Alembic environment is a bit complicated at the moment and duplicates a bit of Safir code. A lot of this can be lifted into Safir in the future. Fix a few problems with secret loading uncovered by loading the example configuration: the example OIDC client secrets were missing the new return_uri field, and newlines weren't removed from the end of secrets.
Oh, and that uncovered another bug: I was running |
It's not generally safe to run Alembic upgrades on startup since we may have multiple replicas, and it's not safe to run gafaelfawr init before Alembic because it will stap the database with the current version even though it didn't make all the required changes. Drop both from the startup script for now. We will need to find a better way of doing both database initialization and schema changes, probably using Helm hooks.
ffb6faf
to
92e0c8a
Compare
Add a new oidc token type as an initial migration, which is not yet used but will be used in a subsequent change.
Use an async engine for Alembic, since that avoids needing to also install psycopg2 alongside asyncpg only for Alembic to use it. Since Alembic only sort-of supports async via asyncio.run, this requires moving the body of gafaelfawr init into a separate coroutine and running that with asyncio.run so that Alembic can be run outside of the running async loop.
The Alembic environment is a bit complicated at the moment and duplicates a bit of Safir code. A lot of this can be lifted into Safir in the future.
Fix a few problems with secret loading uncovered by loading the example configuration: the example OIDC client secrets were missing the new return_uri field, and newlines weren't removed from the end of secrets.