diff --git a/db_helpers.py b/db_helpers.py index 1b83892..5dfad16 100644 --- a/db_helpers.py +++ b/db_helpers.py @@ -1,4 +1,6 @@ r"""Gemeinsame DB-Zugriffe (Benutzer + Admin-Bootstrap).""" +import pymysql + from db import get_connection from config import Config from auth import hash_password @@ -30,12 +32,25 @@ def create_user(username: str, password: str, email: str = "", is_admin: bool = def ensure_admin(app): - """Legt beim ersten Start den Admin aus den Env-Variablen an, falls keiner existiert.""" + """Legt beim ersten Start den Admin an, falls er nicht existiert. + + Race-sicher: Da Gunicorn mehrere Worker startet, rufen alle zugleich + create_app() auf. Die Prüfung + Einfügen ist deshalb nicht atomar – + ein IntegrityError (Duplicate key) wird daher toleriert, wenn ein + anderer Worker den Admin bereits angelegt hat. + """ with app.app_context(): with get_connection() as conn: with conn.cursor() as cur: - cur.execute("SELECT COUNT(*) AS c FROM users WHERE is_admin = 1") + cur.execute( + "SELECT COUNT(*) AS c FROM users WHERE username = %s", + (Config.ADMIN_USERNAME,), + ) count = cur.fetchone()["c"] if count == 0: - create_user(Config.ADMIN_USERNAME, Config.ADMIN_PASSWORD, is_admin=True) - print(f"Admin-Benutzer '{Config.ADMIN_USERNAME}' angelegt.") + try: + create_user(Config.ADMIN_USERNAME, Config.ADMIN_PASSWORD, is_admin=True) + print(f"Admin-Benutzer '{Config.ADMIN_USERNAME}' angelegt.") + except pymysql.err.IntegrityError: + # Ein anderer Worker hat den Admin bereits erstellt. + pass