From 2a3482c2c008566045fda46908abdb30e387c78e Mon Sep 17 00:00:00 2001 From: Yuyao Huang Date: Sat, 9 May 2026 10:19:58 +0800 Subject: [PATCH] fix: prevent UNIQUE constraint race with gunicorn multi-worker Use INSERT OR IGNORE instead of SELECT-then-INSERT for default admin user creation, avoiding the race condition when multiple gunicorn workers initialize simultaneously. --- README.md | 2 ++ schema.py | 20 +++++++++----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6baec4d..0ba73fc 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ uv add gunicorn uv run gunicorn -w 4 -b 0.0.0.0:5000 app:app ``` +> **Note:** The `-b` flag is required because gunicorn is a separate WSGI server and does not read Flask's `config.py`. The values in `config.py` (`HOST`, `PORT`) only apply to Flask's built-in dev server (`app.run()`). + ## Project Structure ``` diff --git a/schema.py b/schema.py index 8a2d912..a9e1f02 100644 --- a/schema.py +++ b/schema.py @@ -86,16 +86,14 @@ def init_db(): conn.commit() import bcrypt - cur = conn.execute("SELECT COUNT(*) FROM users WHERE role = 'admin'") - if cur.fetchone()[0] == 0: - password_hash = bcrypt.hashpw( - config.DEFAULT_ADMIN_PASSWORD.encode("utf-8"), - bcrypt.gensalt() - ).decode("utf-8") - conn.execute( - "INSERT INTO users (username, password_hash, role, max_goals) VALUES (?, ?, ?, ?)", - (config.DEFAULT_ADMIN_USERNAME, password_hash, "admin", 100) - ) - conn.commit() + password_hash = bcrypt.hashpw( + config.DEFAULT_ADMIN_PASSWORD.encode("utf-8"), + bcrypt.gensalt() + ).decode("utf-8") + conn.execute( + "INSERT OR IGNORE INTO users (username, password_hash, role, max_goals) VALUES (?, ?, ?, ?)", + (config.DEFAULT_ADMIN_USERNAME, password_hash, "admin", 100) + ) + conn.commit() finally: conn.close()