2009-06-04 30 views
16

Có cách nào để chạy một số mã sau khi giao dịch cam kết trong Django?chạy mã sau khi giao dịch cam kết trong Django

Tôi cần gửi một số thư tới máy chủ thỏmq để xử lý ngoại tuyến, nhưng thư được gửi đến người tiêu dùng trước khi giao dịch Django được cam kết.

Tin nhắn của tôi được gửi trong tín hiệu post_save của mô hình. Những gì tôi đang tìm kiếm là một cơ chế tương tự, sử dụng tín hiệu hoặc cái gì khác, mà sẽ thực thi mã sau khi cam kết (và không làm gì nếu giao dịch thất bại).

Tôi chưa tìm thấy bất kỳ cách chung nào để thực hiện việc đó ở Django. Bạn có bất cứ ý tưởng?

+1

Tôi đã có một vấn đề simmilar. Trên post_save, Publisher (quy trình 1) lưu trạng thái nhiệm vụ và xuất bản tin nhắn. Người tiêu dùng (quy trình 2) nhận được thông báo và cập nhật trạng thái tác vụ, hiện chưa có trong db. Điều gì đã làm cho người tiêu dùng ngủ trong một hoặc hai giây sau khi nhận được tin nhắn. Cảm thấy bẩn anyway. – ohnoes

+0

Sau khi đấu tranh trong 4 giờ, tôi đã tìm ra từ câu hỏi này rằng chúng tôi không thể có mã sau transaction.commit() và bây giờ mã của tôi đang chạy tốt. cảm ơn. – zubinmehta

+0

Vé liên quan: https: //code.djangoproject.com/ticket/14051 – guettli

Trả lời

11

CẬP NHẬT 2: django-transaction-hooks là merged into Django core và được phát hành ở phiên bản Django 1.9.

CẬP NHẬT: django-transaction-hooks giải quyết vấn đề này.

Tôi không tin rằng có một cách sạch sẽ để làm điều này; ít nhất tôi cũng không thể nghĩ ra. Bạn có thể monkeypatch django.db.transaction.commit để gửi tín hiệu tùy chỉnh; không đẹp nhưng tôi nghĩ nó sẽ hoạt động.

Cũng có thể thú vị khi tăng trường hợp sử dụng này lên django-developers mailing list. Các nhà phát triển thường không thích thêm các tín hiệu mới, nhưng bạn có thể có một trường hợp tốt ở đây (và một sự bác bỏ từ một nhà phát triển cốt lõi có thể bao gồm một gợi ý hữu ích về cách giải quyết tình huống của bạn). Bạn có nhiều khả năng để có được phản ứng nếu bạn chờ đợi cho đến khi sau 1.1 đi ra, mặc dù.

+0

Tôi phải làm việc trên một số phần khác của ứng dụng trước đây, nhưng tôi sẽ đi theo con đường này. Khi nó đã sẵn sàng, tôi sẽ thả một e-mail để phát triển django và thêm một báo cáo lỗi với các bản vá. –

+0

Nếu 'django-transaction-hooks' yêu cầu phiên bản Django quá cao, bạn có thể sử dụng' django-db-signal'. – r3m0t

1

Một khả năng sẽ là phân lớp trung gian giao dịch để nó gửi tín hiệu tùy chỉnh trên cam kết. Mã của bạn có thể nghe cho tín hiệu đó, thay vì post_save.

+0

Cảm ơn, tôi nghĩ rằng tôi sẽ đi với một số phần mềm trung gian (tôi có lẽ sẽ thêm một phần mềm trung gian khác và không phân lớp phần mềm trung gian giao dịch). Tôi có lo ngại về tín hiệu. Họ có an toàn không? Nếu một luồng khác ném tín hiệu, thì luồng hiện tại có bắt được nó không? –

+0

Tôi vẫn gặp sự cố với phần giữa: nếu ứng dụng đang chạy từ lệnh quản lý, nó sẽ không thực thi cuộc gọi lại của tôi. –

+0

Tôi không nghĩ câu hỏi về chuỗi của bạn thực sự có ý nghĩa. Tín hiệu không làm bất cứ điều gì đặc biệt liên quan đến chủ đề. Một tín hiệu được gửi trong một luồng sẽ chỉ gọi các bộ thu trong cùng một chuỗi đó. Các đối tượng tín hiệu tích hợp là mô-đun toàn cục, tuy nhiên, do đó một trình xử lý tín hiệu đã đăng ký cho post_save trong một luồng được đăng ký trong tất cả các luồng. (Tôi nghĩ rằng nó có thể có thể có các đối tượng tín hiệu trong mã của riêng bạn mà không phải là toàn cầu, đã không nhìn vào nó một cách cẩn thận). –

1

Có một cái nhìn tại django-celery-transactions kiếm một giải pháp cho việc này.

Gần đây tôi đã hoàn thành việc tách ra và tái cấu trúc mã mã tín hiệu cơ bản thành ứng dụng độc lập django-db-signals.

5

Hy vọng điều này có thể giúp ai đó sử dụng Django 1.9 trở lên. Kể từ 1.9 on_commit khả dụng.

Vì vậy, về cơ bản bạn sẽ được làm việc đó như thế này:

from django.db import transaction 

transaction.on_commit(
    lambda: send_msg_to_rabbitmqp(param1, param2, ...) 
) 

Nếu bạn muốn giữ lại post_save, bạn vẫn có thể sử dụng on_commit:

@receiver(pre_save, sender=MyModel) 
def my_handler(sender, instance, created, **kwargs): 
    transaction.on_commit(
     lambda: send_msg_to_rabbitmqp(instance.id) 
    ) 
Các vấn đề liên quan