Cách tôi xây dựng hệ thống đồng bộ hóa "Set It and Forget It"

Giá sản phẩm thay đổi ở nhiều nơi. Chúng thay đổi trong bảng điều khiển admin, thông qua nhập dữ liệu hàng loạt (bulk imports), hoặc qua API webhooks.

Nếu bạn muốn đồng bộ hóa những thay đổi này với một sàn thương mại điện tử bên ngoài, bạn sẽ gặp vấn đề. Thêm một lệnh gọi đồng bộ vào mọi luồng mã (code path) là một sai lầm. Bạn sẽ quên một chỗ. Bạn sẽ làm hỏng một chỗ. Việc bảo trì sẽ trở thành một cơn ác mộng.

Django signals giải quyết vấn đề này. Bạn móc (hook) vào sự kiện lưu model (model save event). Điều này giúp bắt mọi thay đổi tại một nơi duy nhất.

Nhưng signals có một nhược điểm. Nếu bạn cập nhật 100 mức giá cùng lúc, signal sẽ kích hoạt 100 lần. Điều này dẫn đến 100 lệnh gọi API. Bạn sẽ chạm ngưỡng giới hạn tốc độ (rate limits) hoặc lãng phí tài nguyên.

Tôi sử dụng một mô hình gồm ba phần để khắc phục điều này:

• Một signal handler thu thập các ID thay vì thực hiện hành động ngay lập tức. • Một set theo từng thread để loại bỏ các ID trùng lặp. • Một callback flush sử dụng transaction.on_commit để xử lý mọi thứ cùng một lúc.

Dưới đây là cách nó hoạt động.

  1. Sử dụng threading.local() Đừng sử dụng biến toàn cục (global variable). Biến toàn cục chia sẻ trạng thái giữa các request. Điều này dẫn đến rò rỉ dữ liệu. threading.local() giữ dữ liệu cô lập trong một thread duy nhất.

  2. Ghi lại, đừng thực hiện ngay Signal handler chỉ đơn giản là thêm ID sản phẩm vào một set. Sau đó, nó yêu cầu Django chạy một hàm flush chỉ sau khi giao dịch cơ sở dữ liệu (database transaction) thành công. Điều này ngăn việc đồng bộ dữ liệu đã lưu thất bại.

  3. Xử lý theo lô (Batch) Khi giao dịch được commit, hàm flush sẽ chạy. Nó sao chép set đó và xóa sạch nó. Sau đó, nó gửi toàn bộ danh sách ID đến một lớp dịch vụ (service layer).

Lớp dịch vụ thực hiện một truy vấn hàng loạt (bulk query) để lấy tất cả sản phẩm. Nó nhóm chúng theo cửa hàng. Cuối cùng, nó gửi một tác vụ duy nhất đến Celery cho mỗi cửa hàng.

Lợi ích rất rõ ràng:

Bạn chỉ cần xây dựng hệ thống một lần. Mọi tính năng mới bạn thêm vào sau này sẽ tự động hoạt động với hệ thống đồng bộ hóa.

Bạn xử lý việc đồng bộ API bên ngoài trong Django như thế nào? Bạn sử dụng signals hay một mô hình khác?

Source: https://dev.to/acel/how-i-built-a-set-it-and-forget-it-sync-system-with-django-signals-2ld7