2012-09-05 23 views
5

thiết lập của tôi:Node.js + Mongo + cập nhật nguyên tử của nhiều đơn vị = đầu đau

  1. Node.js
  2. Mongojs
  3. Một cơ sở dữ liệu đơn giản có chứa hai bộ sưu tập - hàng tồn kho và hóa đơn.
  4. Người dùng có thể đồng thời tạo hóa đơn.
  5. Hóa đơn có thể tham chiếu đến một số mục khoảng không quảng cáo.

Vấn đề của tôi:

Giữ nguyên vẹn hàng tồn kho. Hãy tưởng tượng một kịch bản là hai người dùng gửi hai hóa đơn với các bộ mặt hàng trùng lặp.

Một ngây thơ (và sai) thực hiện sẽ làm như sau:

  1. Đối với mỗi mục trong hóa đơn đọc mục tương ứng từ bộ sưu tập hàng tồn kho.
  2. Khắc phục số lượng các mục khoảng không quảng cáo.
  3. Nếu bất kỳ số lượng mặt hàng nào dưới 0 - hãy từ chối yêu cầu có thông báo liên quan đến người dùng.
  4. Lưu các mục khoảng không quảng cáo.
  5. Lưu hóa đơn.

Rõ ràng, việc triển khai này là xấu, bởi vì các hành động của hai người dùng sẽ xen kẽ và ảnh hưởng lẫn nhau. Trong một máy chủ chặn điển hình + cơ sở dữ liệu quan hệ, giải pháp này được giải quyết bằng các lược đồ khóa/giao dịch phức tạp.

Cách thức xao xuyến + mong manh để giải quyết vấn đề này là gì? Có bất kỳ công cụ nào mà nền tảng node.js cung cấp cho những thứ này không?

+0

Bạn đã xem phương pháp cam kết hai giai đoạn MongoDB được đề xuất mô tả [ở đây] (http://cookbook.mongodb.org/patterns/perform-two-phase-commits/)? – JohnnyHK

Trả lời

5

Bạn có thể xem xét một cách tiếp cận hai pha cam kết với MongoDB, hoặc bạn có thể quên các giao dịch hoàn toàn và tách các quy trình của bạn thông qua một phương pháp tiếp cận dịch vụ xe buýt. Sử dụng Amazon làm ví dụ - chúng sẽ cho phép bạn gửi đơn đặt hàng của bạn, nhưng họ sẽ không xác nhận đơn đặt hàng cho đến khi họ có thể đảm bảo mục hàng tồn kho của bạn, tính phí thẻ của bạn, v.v. Không có điều gì xảy ra trong một giao dịch duy nhất - đó là một loạt các bước có thể xảy ra trong sự cô lập và có thể có các bước bù trừ được áp dụng khi cần thiết.

Một triển khai xe buýt ngây thơ sẽ làm như sau (lưu ý rằng đây chỉ là một gợi ý chung chung để bạn có thể làm việc từ và thực hiện chính xác sẽ phụ thuộc vào nhu cầu của bạn cụ thể cho đồng thời, vv):

  1. đặt hàng trên hàng đợi. Tại thời điểm này, bạn có thể tiếp tục yêu cầu khách hàng của bạn chờ đợi hoặc bạn có thể cảm ơn họ vì đơn đặt hàng của họ và cho họ biết họ sẽ nhận được email khi được xử lý .
  2. "công nhân hàng tồn kho" sẽ lấy đơn đặt hàng và khóa khoảng không quảng cáo các mặt hàng cần lưu trữ. Điều này có thể được thực hiện theo nhiều cách khác nhau . Với Mongo bạn có thể tạo một bộ sưu tập có một tài liệu cho mỗi orderid. Tài liệu này sẽ có ID của nó là ID mục hàng tồn kho và TTL là hợp lý (nói 30 giây).Miễn là người lao động có khóa, thì có thể quản lý mức khoảng không quảng cáo của các mục mà nó đã khóa. Sau khi thực hiện các thay đổi, nó có thể xóa tài liệu "khóa".
  3. Nếu một công nhân khác đi cùng muốn quản lý cùng một mục trong khi bị khóa, bạn có thể đưa nhân viên bị chặn vào chế độ ngủ trong X giây và sau đó thử lại hoặc, tốt hơn, bạn có thể đặt lại yêu cầu xe buýt nhắn tin được một công nhân khác đón tiếp.
  4. Sau khi nhân viên đã giải quyết tất cả các mục hàng tồn kho, sau đó có thể đặt một thông báo khác trên xe buýt dịch vụ cho biết cần phải trả phí hoặc xử lý thông báo để kéo khoảng không quảng cáo hoặc email được gửi đến người đã thực hiện đơn đặt hàng, v.v., v.v.

Âm thanh phức tạp, nhưng một khi bạn có thiết lập bus thông báo thì thực sự tương đối đơn giản. A list of Node Message Bus Implementations can be found here.

Một số nhà phát triển thậm chí sẽ bỏ qua hoàn toàn thông báo xe buýt chính thức và sử dụng cơ sở dữ liệu làm công cụ truyền tin nhắn của họ có thể hoạt động trong các triển khai đơn giản. Google Mongo và Hàng đợi.

Nếu bạn không mong đợi nhiều hơn 1 máy chủ và việc triển khai bus thông báo quá cồng kềnh, nút có thể xử lý khóa và thông báo cho bạn. Ví dụ: nếu bạn thực sự muốn khóa bằng nút, bạn có thể tạo một mảng lưu trữ ID mục hàng tồn kho. Mặc dù, để thẳng thắn, tôi nghĩ rằng xe buýt nhắn tin là cách tốt nhất để đi. Dù sao, đây là một số mã tôi đã sử dụng trong quá khứ để xử lý khóa tài nguyên bên ngoài đơn giản với Node.

// attempt to take out a lock, if the lock exists, then place the callback into the array. 
this.getLock = function(id, cb) { 

     if(locks[id]) { 
      locks[id].push(cb); 
      return false; 
     } 
     else { 
      locks[id] = []; 
      return true; 
     } 
    }; 

// call freelock when done 
this.freeLock = function(that, id) { 
      async.forEach(locks[id], function(item, callback) { 
       item.apply(that,[id]); 
       callback(); 
      }, function(err){ 
       if(err) { 
        // do something on error 
       } 

       locks[id] = null; 

      }); 
     }; 
+0

Cảm ơn bạn rất nhiều, có vẻ tuyệt vời. – mark

+0

Có điều gì đó tôi không hiểu - những gì có thể được thực hiện nếu một lỗi xảy ra trong ví dụ của bạn? Phần đặt bình luận "làm điều gì đó về lỗi" được đặt. Tôi muốn dính vào điều đơn giản nhất bây giờ - một máy chủ duy nhất và một yêu cầu trở lại với kết quả, dù tốt hay xấu, nhưng không có công việc chạy dài. Máy chủ là một quá trình nút duy nhất, vì vậy bạn có ý nghĩa gì bởi một nhân viên kiểm kê? – mark

Các vấn đề liên quan