Chạy database migration khi deploy, nên hay không?
Có một thủ pháp thường hay được sử dụng khi deploy app là chạy database migration ngay khi deploy, nhưng liệu đó có phải là một good practice (tam dịch: cách làm tốt) hay không? Tất nhiên, để đảm bảo tính khách quan, mình giữ lập trường “câu trả lời vẫn luôn là còn tùy”, ...
Có một thủ pháp thường hay được sử dụng khi deploy app là chạy database migration ngay khi deploy, nhưng liệu đó có phải là một good practice (tam dịch: cách làm tốt) hay không?
Tất nhiên, để đảm bảo tính khách quan, mình giữ lập trường “câu trả lời vẫn luôn là còn tùy”, nhưng 99.9999% trường hợp là KHÔNG.
Giả sử ta có một app cần phải đổi tên cột dob của bảng users thành date_of_birth.
Dễ ợt như a ă â đúng không, ta chỉ cần một đoạn code migration như sau.
1 2 3 4 5 |
def change rename_column "users", :dob, :date_of_birth end |
Và trong đoạn code trả về cho người dùng.
1 2 3 4 5 6 7 |
# trước khi sửa render_json({id: user.id, date_of_birth: user.dob}) # sau khi sửa render_json({id: user.id, date_of_birth: user.date_of_birth}) |
Như đầu đề, ta sẽ chạy migration code cùng lúc với deploy. Có thể nó khá phức tạp tùy theo từng app nhưng chung quy lại gồm 3 bước: a) Kéo code mới từ SCM về b) chạy đoạn code migration ở trên và c) restart lại ứng dụng để áp dụng mã mới.
Vậy thì vấn đề của cách làm trên là ở đâu?
Vấn đề
Có thể bạn sẽ để ý được là ở khoảng thời gian sau b) cho tới khi c) kết thúc, phần API đọc và ghi users của bạn sẽ bị lỗi không ngừng nghỉ với rate là 100%, lý do là vì lúc đó cột dob đã bị gỡ khỏi database nhưng code mới thì chưa được release lên.
Đương nhiên bạn có thể đảo ngược thứ tự giữa b) và c) nhưng vấn đề không đổi, cột date_of_birth chưa được tạo.
Là một lập trình viên, đôi lúc bạn sẽ nghĩ là vài giây đó thì thấm tháp vào đâu, nhưng chắc chắn 99.99% đồng nghiệp của bạn đang làm cho bộ phận tiếp nhận phàn nàn từ khách hàng sẽ nghĩ khác, những phần tử trong 0.001% còn lại (ừ thì 1 + 1 = 3) chắc hết chiều hôm đó thôi việc.
Giải pháp
Không có một giải pháp chuẩn nào cho việc này cả nhưng nói một cách hàn lâm thì quy tắc chung là:
Đảm bảo bản deploy hiện tại tương thích với bản deploy trước ở bất kì thời điểm nào của deploy.
Vậy với vấn đề ở trên (định dùng chữ bài toán nhưng sợ bạn rule keeper ở #random phàn nàn) cách giải quyết là chia thành nhiều bản deploy nhỏ (chú ý mỗi bước sau đây là một bản deploy).
a) tạo ra cột date_of_birth trong bảng users.
b) sửa đoạn code ghi ngày sinh và đoạn code đọc ngày sinh.
1 2 3 4 5 6 7 8 9 |
## ghi User.update(user_id, date_of_birth: params[:dob]) ## đọc user = User.read(user_id) date_of_birth = user.date_of_birth || user.dob render_json({id: user.id, date_of_birth: date_of_birth) |
c) Viết đoạn script migrate tất cả dữ liệu từ dob qua date_of_birth.
d) Xóa đoạn code đọc đi (đừng xóa đoạn viết nếu bạn không muốn đồng nghiệp quay qua hỏi thăm bằng tiếng Đan Mạch).
e) Tạo migration để xóa cột dob.
Kết luận
Quản lý database schema là một vấn đề khó và đòi hỏi sự cẩn thận, tốt nhất là bạn nên đùn công việc này cho người khác nếu có thể (troll đó cơ mà nếu đùn được thì tốt).
Các bước thực hiện có thể sẽ khác nhau tùy trường hợp nhưng ý tưởng cơ bản thì là như trên, bạn có thể xào nấu lại tùy thích.
Techtalk Via hqc.io