-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move dev DB creation to a separate process
Context ------- At startup (when you run `make dev`) Via's Gunicorn processes attempt to create the DB tables if they don't already exist. This is done in dev only, not in production: # via/db.py def includeme(config): ... if config.registry.settings.get("dev"): # Create the database tables if they don't already exist. Base.metadata.create_all(engine) Problem ------- Via actually has four Gunicorn workers in dev (see the `workers = 4` in `conf/gunicorn/dev.conf.py`). All 4 try to create the DB tables at the same time and 3 of them crash, printing out error messages. The issue is kind of difficult to reproduce: 1. You need to actually have a model, so you won't be able to produce the issue on the `db` branch without changes. See #1072 and #1093 for branches on which you can reproduce the issue. 2. The model's table needs to actually be missing from the DB table. You can do that by running this command: make services args=down && make services && make dev 3. Since the issue is a race condition you won't be able to reproduce it reliably, but if you run the above command several times you should see it. Solution -------- This commit moves the `sqlalchemy.create_all()` call out of the Gunicorn worker process and instead adds a separate `make_db` process to the list of processes that `supervisord-dev.conf` runs when you run `make dev`. This new `make_db` process starts up, calls `create_all()`, and then exits, and since it's a singular process there's no collision.
- Loading branch information
Showing
4 changed files
with
51 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,35 @@ | ||
"""Initialize the dev environment's DB.""" | ||
#!/usr/bin/env python3 | ||
import sys | ||
"""Initialize the dev environment's DB.""" | ||
import alembic.command | ||
import alembic.config | ||
from pyramid.paster import bootstrap | ||
bootstrap("conf/development.ini") | ||
from sqlalchemy import text | ||
from sqlalchemy.exc import ProgrammingError | ||
|
||
from via.db import Base, create_engine | ||
|
||
|
||
def is_stamped(engine) -> bool: | ||
"""Return True if the DB is stamped with an Alembic revision ID.""" | ||
with engine.connect() as connection: | ||
try: | ||
if connection.execute(text("select * from alembic_version")).first(): | ||
return True | ||
except ProgrammingError: | ||
pass | ||
|
||
return False | ||
|
||
|
||
def main(): | ||
with bootstrap("conf/development.ini") as env: | ||
settings = env["registry"].settings | ||
engine = create_engine(settings) | ||
|
||
if not is_stamped(engine): | ||
Base.metadata.create_all(engine) | ||
alembic.command.stamp(alembic.config.Config("conf/alembic.ini"), "head") | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters