2013-04-27 65 views
7

Một cái gì đó mà tôi chỉ nghĩ về:Điều gì xảy ra khi bạn có vòng lặp vô hạn trong mã xem Django?

Giả sử tôi đang viết mã xem cho trang web Django của mình và tôi mắc lỗi và tạo vòng lặp vô hạn.

Bất cứ khi nào ai đó cố gắng truy cập chế độ xem, nhân viên được chỉ định cho yêu cầu (có thể là nhân viên Gevent hoặc chuỗi Python) sẽ ở trong vòng lặp vô thời hạn.

Nếu tôi hiểu chính xác, máy chủ sẽ gửi lỗi hết thời gian chờ tới máy khách sau 30 giây. Nhưng điều gì sẽ xảy ra với công nhân Python? Nó sẽ tiếp tục hoạt động vô thời hạn? Nghe có vẻ nguy hiểm!

Hãy tưởng tượng tôi có một máy chủ trong đó tôi đã phân bổ 10 công nhân. Tôi để cho nó chạy và tại một số điểm, một khách hàng cố gắng truy cập vào khung nhìn với vòng lặp vô hạn. Một nhân viên sẽ được gán cho nó, và sẽ có hiệu lực chết cho đến khi máy chủ tiếp theo khởi động lại. Điều nguy hiểm là lúc đầu tôi sẽ không nhận ra điều đó, bởi vì trang web sẽ chậm hơn đáng kể, có 9 công nhân thay vì 10. Nhưng sau đó nó có thể xảy ra lặp đi lặp lại trong một khoảng thời gian dài, có thể vài tháng. Trang web sẽ chỉ chậm dần, cho đến khi cuối cùng nó sẽ rất chậm chỉ với một công nhân.

Khởi động lại máy chủ sẽ giải quyết được sự cố, nhưng tôi ghét phải có chức năng của trang web phụ thuộc vào khởi động lại máy chủ.

Đây có phải là sự cố thực sự xảy ra không? Có cách nào để tránh không?

Cập nhật: Tôi cũng thực sự đánh giá cao cách lấy chồng của chuỗi/công nhân bị kẹt trong vòng lặp vô hạn, vì vậy tôi có thể gửi email cho tôi để tôi biết vấn đề . (Tôi không biết làm thế nào để làm điều này bởi vì không có ngoại lệ nào được nêu ra.)

Cập nhật để mọi người nói về ảnh hưởng của "Tránh viết mã có vòng lặp vô hạn": Trong trường hợp không phải là hiển nhiên, tôi không dành thời gian rảnh để cố tình đưa các vòng vô hạn vào mã của mình. Khi những điều này xảy ra, chúng là những sai lầm, và những sai lầm có thể được giảm thiểu nhưng không bao giờ hoàn toàn tránh được. Tôi muốn biết rằng ngay cả khi tôi phạm sai lầm, sẽ có một mạng lưới an toàn sẽ thông báo cho tôi và cho phép tôi khắc phục vấn đề.

+2

thú đọc: http: // stackoverflow. com/questions/8685695/how-do-i-run-long-term-infinite-python-processes –

+0

Tôi đã cập nhật câu trả lời của mình, tôi hy vọng nó sẽ trả lời câu hỏi của bạn ngay bây giờ :) –

Trả lời

4

Đó là một vấn đề thực sự. Trong trường hợp của gevent, do bối cảnh chuyển đổi, nó thậm chí có thể ngay lập tức ngừng trang web của bạn từ đáp ứng.

Mọi thứ phụ thuộc vào môi trường của bạn. Ví dụ, khi chạy django trong sản xuất thông qua uwsgi bạn có thể đặt harakiri - đó là thời gian tính bằng giây, sau đó xử lý chuỗi yêu cầu sẽ bị giết nếu nó không xử lý xong phản hồi. Chúng tôi khuyên bạn nên đặt một giá trị như vậy để xử lý một số yêu cầu bị lỗi hoặc mã lỗi. Sự kiện như vậy được báo cáo trong nhật ký uwsgi. Tôi tin rằng các giải pháp khác để chạy Django trong sản xuất có các tùy chọn tương tự.

Nếu không, do kiến ​​trúc mạng, ngắt kết nối máy khách sẽ không dừng vòng lặp vô hạn và theo mặc định sẽ không có phản hồi nào cả - chỉ tải vô hạn. Các tùy chọn thời gian chờ khác nhau (một trong số đó là harakiri) có thể kết thúc hiển thị thời gian chờ kết nối - ví dụ, php có (theo như tôi nhớ) thời gian chờ mặc định là 30 giây và nó sẽ trả về thời gian chờ của cổng 504. Thời gian chờ ngắt kết nối phụ thuộc vào cài đặt máy chủ http và nó sẽ không dừng thread ứng dụng, nó sẽ chỉ đóng ổ cắm máy khách.

Nếu không sử dụng gevent (hoặc bất kỳ chủ đề màu xanh lá cây nào khác), vòng lặp vô hạn sẽ có xu hướng chiếm 100% công suất CPU sẵn có (giới hạn một lõi), có thể ăn nhiều bộ nhớ hơn, vì vậy trang web của bạn sẽ hoạt động tốt chậm và/hoặc thời gian chờ thực sự nhanh chóng. Bản thân Django không nhận thức được thời gian yêu cầu, vì vậy - như đã đề cập trước đây - ngăn xếp môi trường sản xuất của bạn là cách ngăn chặn điều này xảy ra. Trong trường hợp của uwsgi, http://uwsgi-docs.readthedocs.org/en/latest/Options.html#harakiri-verbose là con đường để đi.

Harakiri không in dấu vết ngăn xếp của Proces giết: (https://uwsgi-docs.readthedocs.org/en/latest/Tracebacker.html?highlight=harakiri) thẳng đến uwsgi đăng nhập, và do hệ thống báo động, bạn có thể nhận được thông báo qua e-mail (http://uwsgi-docs.readthedocs.org/en/latest/AlarmSubsystem.html)

+0

Tùy chọn Harakiri là một bước đi đúng hướng, vì nó dừng máy chủ bị kẹt, nhưng nó không giúp bạn tìm ra gốc rễ của vấn đề và sửa chữa nó. Những gì tôi muốn là có một stacktrace của công nhân vi phạm gửi qua email cho tôi vì vậy tôi có thể kiểm tra nó và sửa chữa vấn đề trong mã. –

+0

Harakiri in dấu vết ngăn xếp và thông tin yêu cầu, và hệ thống báo động nginx cho phép thông báo e-mail. Đã cập nhật câu trả lời với các liên kết. –

+0

Xin lỗi, tôi có nghĩa là hệ thống báo động uwsgi tất nhiên :) –

0

Có, phân tích của bạn là chính xác. Chuỗi/quy trình công nhân sẽ tiếp tục chạy. Hơn nữa, nếu không có chờ đợi/ngủ trong vòng lặp, nó sẽ hog CPU. Các chủ đề/quy trình khác sẽ nhận được rất ít CPU, dẫn đến toàn bộ trang web của bạn phản hồi chậm.

Ngoài ra, tôi không nghĩ rằng máy chủ sẽ gửi bất kỳ lỗi hết thời gian chờ nào cho khách hàng một cách rõ ràng. Nếu thời gian chờ TCP được đặt, kết nối TCP sẽ bị đóng.

Khách hàng cũng có thể có một số cài đặt thời gian chờ để nhận phản hồi, có thể có ảnh.

Tránh mã như vậy là cách tốt nhất để tránh mã như vậy. Bạn cũng có thể có một số công cụ giám sát trên máy chủ để tìm kiếm việc sử dụng CPU/bộ nhớ và thông báo cho hoạt động bất thường để bạn có thể thực hiện hành động.

2

Tôi vừa thử nghiệm điều này trên máy chủ phát triển của Django.

Kết quả:

  • Có không đưa ra một thời gian chờ sau 30 giây.(điều này có thể do nó không phải là máy chủ sản xuất)
  • Vẫn đang tải cho đến khi tôi đóng trang.

Tôi đoán một cách để tránh nó, mà không thực sự chỉ cần tránh một mã như thế, sẽ sử dụng luồng để kiểm soát thời gian chờ và có thể dừng chuỗi.

Có lẽ cái gì đó như:

import threading 
from django.http import HttpResponse 

class MyThread(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
    def run(self): 
     print "your possible infinite loop code here" 

def possible_loop_view(request): 
    thread = MyThread() 
    thread.start() 
    return HttpResponse("html response") 
+0

Thực ra, bây giờ tôi nghĩ về, bạn có thể muốn gọi thread = MyThread() trong một hàm khác để bạn thực sự có thể truy cập nó và dừng nó sau này .. nhưng vẫn là một giải pháp có thể? – Ramalus

+0

Tôi thực sự không hiểu câu trả lời của bạn giải quyết mọi thứ như thế nào. Đối với một điều, mã cần phải hoàn thành * trước * trả lời được trả về. Thứ hai, bạn thậm chí không hiển thị như thế nào các chủ đề bạn tạo ra sẽ được tự động dừng lại. –

+0

Ồ, bạn nói đúng, tôi đoán tôi đã không nghĩ điều này qua rất nhiều. Tôi xin lôi. – Ramalus

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