Cách một React Bundle bị lưu cache đã gửi dữ liệu đến sai cơ sở dữ liệu

Chúng tôi đang chạy đua với deadline. Đội ngũ backend đã chuyển sang một API và cơ sở dữ liệu mới. Đội ngũ frontend đã cập nhật các biến môi trường trong AWS Amplify và đẩy mã nguồn lên.

Việc triển khai đã thành công. Chúng tôi đóng máy tính lại. Chúng tôi nghĩ rằng mọi việc đã xong.

Chúng tôi đã lầm.

Một kỹ sư đã kiểm tra nhật ký (logs) trên máy chủ API cũ. Đáng lẽ máy chủ này phải ngừng hoạt động. Nhưng không. Nó vẫn đang nhận các yêu cầu thực tế từ khách hàng và ghi dữ liệu vào cơ sở dữ liệu cũ.

Trong suốt hai giờ đồng hồ, dữ liệu thực của khách hàng đã bị gửi đến sai nơi.

Dưới đây là lý do tại sao điều đó xảy ra và cách chúng tôi đã khắc phục nó.

Vấn Đề

Các ứng dụng React trên các CDN như AWS Amplify sẽ thay thế các biến môi trường tại thời điểm build. Khi bạn chạy build, trình đóng gói (bundler) sẽ tìm mọi biến và thay thế chúng bằng một chuỗi ký tự được viết cứng (hardcoded).

URL của API đã được nhúng trực tiếp vào tệp JavaScript.

Khi chúng tôi triển khai, những người dùng mới sẽ nhận được bundle mới. Nhưng những người dùng hiện tại đang mở ứng dụng thì không bao giờ tải lại trang. Họ vẫn tiếp tục chạy bundle cũ với URL cũ đã được viết cứng bên trong.

Vì máy chủ cũ vẫn đang chạy, các client này nhận được trạng thái 200 OK. Mọi thứ trông có vẻ ổn. Lỗi xảy ra một cách âm thầm. Sự im lặng là loại lỗi nguy hiểm nhất.

Giải Pháp Ba Lớp

Chúng tôi đã xây dựng ba lớp để đảm bảo điều này không bao giờ lặp lại.

1. Cấu hình tại thời điểm chạy (Runtime Configuration) Chúng tôi đã ngừng việc nhúng trực tiếp các URL vào JavaScript bundle. Thay vào đó, chúng tôi sử dụng một tệp config.json trong thư mục public. Trình đóng gói (bundler) sẽ không chạm vào tệp này. Ứng dụng sẽ lấy tệp này tại thời điểm runtime trước khi render. Điều này đảm bảo các phiên làm việc mới luôn nhận được URL chính xác.

2. Thông báo qua WebSocket Một cấu hình runtime không giúp ích gì cho những người dùng đang mở sẵn một tab. Chúng tôi đã liên kết quy trình triển khai với máy chủ WebSocket của mình. Khi Amplify hoàn tất quá trình build, nó sẽ gọi một webhook trên API của chúng tôi. Sau đó, máy chủ sẽ đẩy một thông báo đến tất cả các client đang kết nối. Nếu người dùng đang ở phiên bản cũ, một biểu ngữ sẽ xuất hiện yêu cầu họ tải lại trang.

3. Quản lý Cache Chúng tôi đã cập nhật các cài đặt CloudFront. Các điểm truy cập như index.htmlconfig.json hiện được thiết lập thành no-cache. Điều này đảm bảo người dùng luôn lấy được các tệp mới nhất thay vì các phiên bản cũ từ một CDN edge node.

Bài Học Rút Ra

• Cấu hình tại thời điểm build (build-time config) là một cái bẫy đối với những giá trị thay đổi giữa các lần triển khai. • Sự im lặng còn nguy hiểm hơn cả tiếng ồn. Hãy để các hệ thống cũ báo lỗi một cách rõ ràng bằng trạng thái 410 Gone. • Áp lực deadline dễ làm hỏng các bước thực hiện thủ công. Hãy tự động hóa quy trình ngừng hoạt động (decommissioning) của bạn. • Hãy giám sát cả những thứ bạn đang tắt đi, chứ không chỉ những thứ bạn đang bật lên.

Triển khai không chỉ đơn thuần là đẩy mã nguồn. Đó còn là việc đảm bảo mọi khách hàng cuối cùng đều đang chạy đúng phiên bản mã nguồn đó.

Nguồn: https://dev.to/sugan_dev/how-a-cached-react-bundle-sent-production-data-to-the-wrong-database-55n9