By hientd, at: 17:53 Ngày 16 tháng 5 năm 2023

Thời gian đọc ước tính: __READING_TIME__ minutes

Flask Migrate - Multi-tenant issues
Flask Migrate - Multi-tenant issues

Gần đây, tôi đã gặp phải một sự cố không mong muốn với Flask-Migrate khi sử dụng đa người thuê với lược đồ PostgreSQL. Hãy để tôi cung cấp một lờ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 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 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 mình:

from models import Task


Tiếp theo, tôi đã chạy lệnh flask db migrate trong thiết bị đầu cuối, lệnh này đã tạo một tệp di chuyển mới trong 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, và tôi đã gặp 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ạ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 lược đồ bằng set schema 'internal';
 

2. Chiến lược giải quyết vấn đề

Để điều tra và gỡ lỗi sự cố, 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 một câu lệnh breakpoint() vào cả hai tệp app.pymigrations/env.py để xác minh xem URI kết nối có chính xác không. URI kết nối có vẻ 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 đề về 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, sự cố vẫn tiếp diễn.

3. Gỡ lỗi sâu:

Tôi đã đặt các câu lệnh breakpoint() vào nhiều hàm trong các thư viện Flask-Migrate, Alembic, và SQLAlchemy, như được chỉ ra 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ỳ thông tin hữu ích hoặc giải pháp 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 góc nhìn mới, 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 nó chính xác, với mật khẩu được ẩ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 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 quay lại với quyết tâm mới.

Sau khi suy ngẫm, 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ó gì đó không ổn với nó. Nó gợi nhớ tôi về kinh 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 có vẻ đơ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 đã suy nghĩ 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 trước đó. 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 ngẫm, 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ó. Do đó, 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 làm theo các thực tiễn tốt nhất sau đây:

  1. 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 xem URI kết nối cơ sở dữ liệu đã được cấu hình chính xác chưa. Hãy chú ý đến IP máy chủ, cổng, tên người dùng, mật khẩu và lược đồ. 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.
  2. 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 phù 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 khả năng tương thích với các thay đổi mới nhất.
  3. Gỡ lỗi kỹ lưỡng: Trong trường hợp bạn gặp 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 có liên quan và tìm kiếm sự trợ giúp từ cộng đồng nếu cần.
  4. Học hỏi từ các framework tương tự: Học hỏi từ kinh nghiệm với các framework khác, chẳng hạn như Django, có thể cung cấp cái nhìn sâu sắc 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 các 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 nguyên tắc 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 động để được hỗ trợ và hướng dẫn. Chúc bạn phát triển Flask vui vẻ!
 

Tag list:
- Python
- Best Practices
- Tips
- Tips and Tricks
- Flask
- Flask-Migrate
- Issues

Liên quan

Python Flask

Đọc thêm
Python Learning

Đọc thêm
Python Learning

Đọc thêm
Theo dõi

Theo dõi bản tin của chúng tôi và không bao giờ bỏ lỡ những tin tức mới nhất.