Flask Migrate - Vấn đề đa người thuê
By hientd, at: 17:53 Ngày 16 tháng 5 năm 2023
Thời gian đọc ước tính: __READING_TIME__ minutes


Gần đây, tôi đã gặp phải một vấn đề không mong muốn với Flask-Migrate khi sử dụng đa thuê nhà với schema PostgreSQL. Hãy để tôi giải thích chi tiết về vấn đề và cách tôi đã giải quyết nó.
Ngoại lệ tôi gặp phải khi chạy lệnh flask db upgrade
là:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "192.9.2.1", port 5432 failed: FATAL: password authentication failed for user "server_username"
connection to server at "192.9.2.1", port 5432 failed: FATAL: no pg_hba.conf entry for host "local", user "server_username", database "proddb", no encryption
Mặc dù mọi thứ hoạt động hoàn hảo trên máy cục bộ của tôi, Flask-Migrate không hoạt động được với cơ sở dữ liệu máy chủ.
1. Vấn đề
Ban đầu, tôi đã cài đặt virtualenv, pip,
và tất cả các gói cần thiết:
psycopg2==2.9.6
Flask==2.3.2
Flask-Migrate==2.5.3
Flask-SQLAlchemy==3.0.3
Tôi đã thiết lập một tệp local.json
cho ứng dụng Flask:
{
"SECRET_KEY": "my secret",
"SQLALCHEMY_DATABASE_URI": "postgresql://joe:password@localhost:5432/testdb",
"DATABASE_SCHEMA": "public"
}
Tệp app.py
chứa mã sau:
import json
from os import environ
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from blueprints import api_blueprint
db = SQLAlchemy()
def create_app():
environment = environ.get("ENVIRONMENT", "local")
app = Flask(__name__)
app.config.from_file(f"{environment}.json", load=json.load)
db.metadata.schema = app.config["DATABASE_SCHEMA"]
db.init_app(app)
migrate = Migrate(app, db)
app.register_blueprint(api_blueprint)
return app
app = create_app()
Ngoài ra, tôi có một tệp main.py
với nội dung sau:
from app import create_app
if __name__ == "__main__":
app = create_app()
app.run(host="127.0.0.1", port=5000, debug=True)
Và cuối cùng, tệp models.py
định nghĩa mô hình Task
:
from app import db
class Task(db.Model):
__tablename__ = "task"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.Text, nullable=False)
Sau khi chạy python main.py
, trang web đã chạy thành công trên 127.0.0.1:5000
Sau khi cài đặt Flask-Migrate==2.5.3
, tôi đã chạy lệnh flask db init
, lệnh này đã tạo ra một thư mục migrations
mới.
Tôi đã cập nhật nội dung của migrations/env.py
bằng cách thêm lớp mô hình của tôi:
from models import Task
Tiếp theo, tôi đã chạy lệnh flask db migrate
trong terminal, lệnh này đã tạo ra một tệp di chuyển mới dưới migrations/versions
, chẳng hạn như migrations/versions/48xw123sdfasf_initial_migration.py
.
Để áp dụng thay đổi này vào cơ sở dữ liệu testdb
mà tôi đã tạo trước đó, tôi đã chạy lệnh sau:
flask db upgrade
Mọi thứ hoạt động hoàn hảo trên máy cục bộ của tôi. Tuy nhiên, khi triển khai lên máy chủ, nơi cơ sở dữ liệu nằm trên một máy chủ khác với IP 192.9.2.1
và cổng 5432
, tôi đã gặp phải sự cố
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "192.9.2.1", port 5432 failed: FATAL: password authentication failed for user "server_username"
connection to server at "192.9.2.1", port 5432 failed: FATAL: no pg_hba.conf entry for host "local", user "server_username", database "proddb", no encryption
Điều đáng ngạc nhiên là tôi có thể kết nối với cơ sở dữ liệu bằng dòng lệnh và truy cập schema bằng set schema 'internal';
2. Chiến lược giải quyết vấn đề
Để điều tra và gỡ lỗi vấn đề, tôi đã làm theo các bước sau:
1. Xác minh URI kết nối cơ sở dữ liệu
Tôi đã chèn câu lệnh breakpoint()
vào cả hai tệp app.py
và migrations/env.py
để xác minh xem URI kết nối có chính xác không. URI kết nối dường như chính xác, với định dạng postgresql://server_username:***@localhost:5432/proddb
. Mật khẩu ẩn (`***`)
dường như là một biện pháp bảo mật để bảo vệ thông tin nhạy cảm.
2. Nâng cấp Flask-Migrate
Xem xét nó có thể là vấn đề phiên bản Flask-Migrate, tôi đã quyết định nâng cấp nó bằng dòng lệnh:
pip install Flask-Migrate==4.0.4 # phiên bản mới nhất
Tuy nhiên, ngay cả sau khi nâng cấp, vấn đề vẫn tồn tại.
3. Gỡ lỗi sâu hơn:
Tôi đã đặt các câu lệnh breakpoint()
trong nhiều hàm khác nhau trong các thư viện Flask-Migrate, Alembic, và SQLAlchemy, như được chỉ định trong lỗi theo dõi Python. Thật không may, những nỗ lực này không cung cấp bất kỳ hiểu biết hoặc giải pháp hữu ích nào. Vấn đề kết nối vẫn tiếp diễn.
Tại thời điểm này, tôi đã nghỉ ngơi một lúc để thư giãn đầu óc và lấy lại sự tập trung.
Trở lại với một cái nhìn mới mẻ, tôi tiếp tục điều tra tệp migrations/env.py
, tệp này đóng vai trò quan trọng trong lệnh flask db upgrade
. Một lần nữa, tôi đã kiểm tra URI kết nối và thấy rằng nó chính xác, với mật khẩu ẩn.
Tuy nhiên, một dòng cụ thể trong tệp migrations/env.py
đã thu hút sự chú ý của tôi:
with connectable.connect() as connection:
Điều tra sâu hơn vào các thư viện (Alembic, SQLAlchemy, và Flask-Migrate), tôi không thể tìm ra bất kỳ giải pháp hoặc bản sửa lỗi nào rõ ràng cho vấn đề này.
Nghỉ ngơi thêm một lúc nữa, lần này kéo dài 15 phút, tôi trở lại với quyết tâm mới.
Sau khi suy nghĩ lại, tôi nhận ra rằng URI với mật khẩu ẩn (`***`)
có thể không phù hợp. Có vẻ như có điều gì đó không ổn với nó. Nó gợi nhớ tôi về những trải nghiệm của tôi với Django, nơi mật khẩu không được che giấu theo cách tương tự. Cách tiếp cận của Django dường như đơn giản hơn.
Với điều này trong tâm trí, tôi quyết định thực hiện một thay đổi. Tôi đã cập nhật `sqlalchemy.url` từ `'postgresql://server_username:***@:5432/proddb'` thành `'postgresql://server_username:server_password@:5432/proddb'`. Điều ngạc nhiên là, sửa đổi này đã giải quyết được vấn đề và quá trình di chuyển đã hoạt động thành công.
Vì vậy, vấn đề là việc ẩn mật khẩu, mật khẩu đã được thay đổi thành `***`, điều này hoàn toàn sai.
Tôi tự hỏi tại sao chủ sở hữu của Flask-Migrate lại chưa xác định và giải quyết vấn đề này sớm hơn. Hoặc ... Có thể tôi đã mắc lỗi, hoặc có thể vấn đề này chỉ đặc thù đối với môi trường của tôi.
Sau khi suy nghĩ lại, tôi nhận ra một lỗi khác mà tôi đã mắc phải trong bước 2.2, nơi tôi đã cài đặt phiên bản mới nhất của Flask-Migrate mà không xóa tệp `migrations/env.py` hiện có và khởi tạo lại nó. Kết quả là, nội dung `env.py` cũ vẫn còn nguyên vẹn.
3. Kết luận
Tóm lại, Flask-Migrate là một công cụ tuyệt vời để di chuyển cơ sở dữ liệu Flask. Để đảm bảo trải nghiệm mượt mà với Flask-Migrate và tránh gặp phải các vấn đề tương tự, điều quan trọng là phải tuân theo các thực tiễn tốt nhất sau:
- Kiểm tra lại URI kết nối cơ sở dữ liệu: Khi triển khai ứng dụng Flask của bạn lên một máy chủ khác, hãy xác minh rằng URI kết nối cơ sở dữ liệu được cấu hình chính xác. Hãy chú ý đến IP máy chủ, cổng, tên người dùng, mật khẩu và schema. Trong một số trường hợp, việc che giấu mật khẩu bằng `***` trong URI có thể gây ra sự cố xác thực, vì vậy hãy đảm bảo mật khẩu được cung cấp một cách rõ ràng.
- Nâng cấp gói đúng cách: Khi nâng cấp Flask-Migrate hoặc bất kỳ gói nào khác, điều quan trọng là phải làm theo quy trình nâng cấp thích hợp. Hãy đảm bảo rằng việc cài đặt thành công và bất kỳ cấu hình hoặc cập nhật nào cần thiết được áp dụng cho phù hợp. Ngoài ra, hãy đảm bảo xóa thư mục `migrations` hiện có và khởi tạo lại nó sau khi nâng cấp Flask-Migrate để đảm bảo tính tương thích với các thay đổi mới nhất.
- Gỡ lỗi kỹ lưỡng: Trong trường hợp bạn gặp phải sự cố với Flask-Migrate, hãy thực hiện gỡ lỗi kỹ lưỡng. Sử dụng các câu lệnh `breakpoint()` một cách chiến lược trong cơ sở mã của bạn để theo dõi luồng thực thi và kiểm tra các biến, cấu hình và thông tin kết nối. Xem xét tài liệu của các thư viện liên quan và tìm kiếm sự trợ giúp từ cộng đồng nếu cần.
- Học hỏi từ các framework tương tự: Học hỏi từ những trải nghiệm với các framework khác, chẳng hạn như Django, có thể cung cấp những hiểu biết về các mẫu và thực tiễn tốt nhất phổ biến cho việc di chuyển cơ sở dữ liệu. Cách tiếp cận của Django đối với kết nối cơ sở dữ liệu và xử lý mật khẩu có thể cung cấp những quan điểm thay thế có thể giúp giải quyết các vấn đề.
Bằng cách tuân thủ các hướng dẫn này và áp dụng phương pháp gỡ lỗi có hệ thống, bạn có thể tối đa hóa lợi ích của Flask-Migrate và khắc phục mọi trở ngại phát sinh trong quá trình di chuyển cơ sở dữ liệu. Hãy nhớ chủ động, cập nhật thông tin và tận dụng cộng đồng Flask sôi nổi để được hỗ trợ và hướng dẫn. Chúc bạn phát triển Flask vui vẻ!