Quần Cam

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”, 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.

def change
  rename_column "users", :dob, :date_of_birth
end

Và trong đoạn code trả về cho người dùng.

# 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)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ĐỪNG CÓ VĂNG LỖI FFS !!!!! ở 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.

## 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.


Lời cuối: Chúc chúng ta không bị banh server và ngủ ngon mỗi đêm.


NGUY HIỂM! KHU VỰC NHIỀU GIÓ!
Khuyến cáo giữ chặt bàn phím và lướt thật nhanh khi đi qua khu vực này.
Chức năng này hỗ trợ markdown và các thứ liên quan.

Bài viết cùng chủ đề

Cache stampede—Hiện tượng chất đống cache

Caching là một kĩ thuật tăng tốc mà hầu như mọi kĩ sư phần mềm đều cần biết. Tuy vậy, đôi khi caching vẫn có thể mang lại cho bạn những vấn đề phiền toái khác như cache stampede.

Monitor Varnish Cache như thế nào?

Varnish Cache là một HTTP reserve proxy giúp tăng tốc web và giảm tải cho backend server của bạn. Bài viết này giới thiệu một số điểm cần chú ý khi monitor Varnish.

Chết server, làm gì đây?

Giả sử server tự dưng lăn đùng ra chết không còn gửi được request nữa, bạn sẽ làm gì?