2009-08-27 26 views
10

Tôi đã viết phần mềm trung gian của riêng mình để cung cấp điểm cuối API cho ứng dụng của chúng tôi. Phần mềm trung gian tải các lớp cung cấp các phương thức API và định tuyến yêu cầu tới lớp/phương thức thích hợp. Các lớp được nạp động qua String#constantize.Dừng tải lại lớp sau khi ngoại lệ không bắt buộc trong phần mềm trung gian tùy chỉnh

Trong khi chạy ở chế độ phát triển, các lớp sẽ tự động được tải lại. Tuy nhiên, nếu có một ngoại lệ vô tình - mà sau đó được xử lý bởi các phần mềm trung gian Failsafe - các tải lại tự động ngừng hoạt động. constantize vẫn đang được gọi nhưng có vẻ như trả lại lớp cũ.

Nó sẽ xuất hiện có cái gì đó khác mà dỡ bỏ các lớp học, và một ngoại lệ uncaught phá vỡ nó. nó có thể là gì?

Chạy Ruby 1.8.7, Rails 2.3.3 và Thin 1.2.2.

+0

Tôi cũng gặp sự cố này. –

Trả lời

0

Rails lưu trữ rất nhiều lớp và tải xuống và tải lại chúng trong chế độ phát triển hoặc khi config.cache_classes được đặt thành true. Dưới đây là một số suy nghĩ về chủ đề này cũng giải thích cách nó hoạt động. http://www.spacevatican.org/2008/9/28/required-or-not/

Không nói với bạn rằng bạn đang làm sai, nhưng quá tải String # constantize có vẻ như một cách hacky để tải lại mã của bạn. Bạn có cân nhắc sử dụng một cái gì đó như watchr để chạy máy chủ ứng dụng của bạn trong quá trình phát triển và khởi động lại nó khi bạn lưu tệp trong cây con API của mình không? https://github.com/mynyml/watchr/

Ngoài ra, đối với một số ý tưởng ngẫu nhiên về cách để tiếp tục gỡ rối, hãy kiểm tra câu trả lời này: https://stackoverflow.com/a/7907289/632022

1

Tôi nghĩ rằng hiệu ứng này xuất phát từ cách ActionController::Reloader được viết. Dưới đây là ActionController::Reloader#call từ 2.3.3, lưu ý những nhận xét:

def call(env) 
    Dispatcher.reload_application 
    status, headers, body = @app.call(env) 
    # We do not want to call 'cleanup_application' in an ensure block 
    # because the returned Rack response body may lazily generate its data. This 
    # is for example the case if one calls 
    # 
    # render :text => lambda { ... code here which refers to application models ... } 
    # 
    # in an ActionController. 
    # 
    # Instead, we will want to cleanup the application code after the request is 
    # completely finished. So we wrap the body in a BodyWrapper class so that 
    # when the Rack handler calls #close during the end of the request, we get to 
    # run our cleanup code. 
    [status, headers, BodyWrapper.new(body)] 
end 

Dispatcher.reload_application không loại bỏ hằng số tự động nạp, Dispatcher.cleanup_application làm. BodyWrapper#close được viết với trường hợp ngoại lệ có thể có trong tâm trí:

def close 
    @body.close if @body.respond_to?(:close) 
ensure 
    Dispatcher.cleanup_application 
end 

Tuy nhiên điều này không giúp đỡ, bởi vì nếu @app.call trong ActionController::Reloader#call ném một ngoại lệ, BodyWrapper không được khởi tạo, và Dispatcher.cleanup_application không được gọi.

Hãy tưởng tượng kịch bản sau đây:

  • tôi có thay đổi trong một tác phẩm của tôi mà ảnh hưởng đến cuộc gọi API
  • Tôi nhấn gọi API và thấy lỗi, vào thời điểm này tất cả các file bao gồm một với một lỗi aren 't bốc dỡ
  • tôi thực hiện một codefix và nhấn cùng gọi API để kiểm tra xem nó làm việc
  • cuộc gọi được chuyển theo cùng một cách như trước, đến các lớp học cũ/đối tượng/modules. Điều này ném lỗi tương tự và một lần nữa để lại các hằng số được nạp trong bộ nhớ

Điều này không xảy ra khi bộ điều khiển truyền thống tăng lỗi vì những điều khiển được xử lý bởi ActionController::Rescue. Ngoại lệ như vậy không trúng ActionController::Reloader.

giải pháp đơn giản nhất sẽ được đưa khoản cứu dự phòng vào API định tuyến trung gian, một số biến thể của việc này:

def call(env) 
    # route API call 
resuce Exception 
    Dispatcher.cleanup_application 
    raise 
end 

Lưu ý rằng đây là câu trả lời của tôi cho câu hỏi cũ 3 năm và theo tiếng gọi của chồng 2.3.3 . Các phiên bản mới hơn của đường ray có thể xử lý mọi thứ khác nhau.

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