Chỉnh sửa lớn: Vì ban đầu tìm thấy vấn đề này tôi đã bỏ nó xuống dưới đây. Tôi nghĩ rằng đây hiện là một mô tả chính xác hơn về vấn đề này là nhẹ. Do đó, các ý kiến về OP có thể không tương quan hoàn toàn.Lỗi luồng khi sử dụng `ActiveRecord with_connection do` & ActionController :: Live
Sửa phiên bản sửa đổi nhẹ posted in ray/dự án puma: https://github.com/rails/rails/issues/21209, https://github.com/puma/puma/issues/758
Sửa Bây giờ sao chép với OS X và Rainbows
Tóm tắt:Khi sử dụng Puma và chạy dài các kết nối đang chạy Tôi luôn nhận các lỗi liên quan đến các kết nối ActiveRecord qua các luồng. Điều này tự hiển thị trong thông báo nhưmessage type 0x## arrived from server while idle
và máy chủ bị khóa (bị lỗi).
Các thiết lập:
- Ubuntu 15/OSX Yosemite
- PostgreSQL (9.4)/MySQL (
mysqld 5.6.25-0ubuntu0.15.04.1
) - Ruby - MRI
2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux]
/Rubiniusrbx-2.5.8
- Rails (
4.2.3
,4.2.1
) - Puma (
2.12.2
,2.11
) - pg (
pg-0.18.2
)/mysql2
Lưu ý, không phải tất cả các kết hợp của các phiên bản trên đã được thử nghiệm. Phiên bản được liệt kê đầu tiên là những gì tôi hiện đang thử nghiệm.
rails new issue-test
- Thêm một tuyến đường
get 'events' => 'streaming#events'
- Thêm một bộ điều khiển
streaming_controller.rb
- Thiết lập thứ cơ sở dữ liệu (
pool: 2
, nhưng nhìn thấy với kích thước hồ bơi khác nhau)
Code:
class StreamingController < ApplicationController
include ActionController::Live
def events
begin
response.headers["Content-Type"] = "text/event-stream"
sse = SSE.new(response.stream)
sse.write({:data => 'starting'} , {:event => :version_heartbeat})
ActiveRecord::Base.connection_pool.release_connection
while true do
ActiveRecord::Base.connection_pool.with_connection do |conn|
ActiveRecord::Base.connection.query_cache.clear
logger.info 'START'
conn.execute 'SELECT pg_sleep(3)'
logger.info 'FINISH'
sse.write({:data => 'continuing'}, {:event => :version_heartbeat})
sleep 0.5
end
end
rescue IOError
rescue ClientDisconnected
ensure
logger.info 'Ensuring event stream is closed'
sse.close
end
render nothing: true
end
end
cấu hình
Puma:
workers 1
threads 2, 2
#...
bind "tcp://0.0.0.0:9292"
#...
activate_control_app
on_worker_boot do
require "active_record"
ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
end
- Run server
puma -e production -C path/to/puma/config/production.rb
thử nghiệm kịch bản:
#!/bin/bash
timeout 30 curl -vS http://0.0.0.0/events &
timeout 5 curl -vS http://0.0.0.0/events &
timeout 30 curl -vS http://0.0.0.0/events
này một cách hợp lý luôn kết quả trong một khóa toàn bộ các máy chủ ứng dụng (trong PostgreSQL, xem ghi chú).Thông điệp đáng sợ đến từ libpq
:
message type 0x44 arrived from server while idle
message type 0x43 arrived from server while idle
message type 0x5a arrived from server while idle
message type 0x54 arrived from server while idle
Trong 'thực tế' Tôi có khá một vài yếu tố phụ và vấn đề trình bày bản thân một cách ngẫu nhiên. Nghiên cứu của tôi chỉ ra rằng thông báo này xuất phát từ libpq
và là nội dung phụ cho vấn đề giao tiếp ', có thể sử dụng kết nối trong các chủ đề khác nhau'. Cuối cùng, khi viết bài này lên, tôi đã khóa máy chủ mà không có một thông báo nào trong bất kỳ nhật ký nào.
Vì vậy, câu hỏi (s):
- là mô hình tôi sau không hợp pháp một cách nào đó? Những gì tôi đã sai [sed | hiểu]?
- 'Chuẩn' để làm việc với các kết nối cơ sở dữ liệu ở đây nên tránh những vấn đề này là gì?
- Bạn có thể thấy cách tái tạo lại điều này một cách đáng tin cậy không?
hoặc
- vấn đề cơ bản ở đây là gì và làm thế nào tôi có thể giải quyết nó?
MySQL
Nếu chạy MySQL, thông điệp là một chút khác nhau, và các ứng dụng phục hồi (mặc dù tôi không chắc chắn nếu nó là sau đó trong một số trạng thái không xác định):
F, [2015-07-30T14:12:07.078215 #15606] FATAL -- :
ActiveRecord::StatementInvalid (Mysql2::Error: This connection is in use by: #<Thread:[email protected]/home/dev/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/live.rb:269 sleep>: SELECT `tasks`.* FROM `tasks` ORDER BY `tasks`.`id` ASC LIMIT 1):
Từ tài liệu ActiveRecord sử dụng with_connection dựa trên khối được chuyển làm đối số hoàn thành. Bạn có chắc là nó đã hoàn thành? Làm thế nào về việc xử lý kết nối với Base.connection hoặc checkout? – Grasshopper
@Grasshopper - cảm ơn! Tôi lo lắng rằng điều này sẽ giữ kết nối mở cho suốt đời của yêu cầu (giờ) do đó ăn hồ bơi kết nối của tôi khá nhanh chóng? Tôi cho rằng cách mà nó có thể không hoàn thành là nếu khối sse.write vì một lý do nào đó và luồng chỉ nằm ở đó, tức là nếu kết nối đã biến mất và nó không trả lại vì một lý do nào đó? (mà nói, tôi không chắc chắn rằng giải thích đầy đủ các vấn đề dựa trên thread-vấn đề từ libpq). (sẽ thử nghiệm với một vài thứ theo hướng đó) – button
Thực tế vấn đề bạn mô tả có thể xảy ra trong các tình huống mà các kết nối không được giải phóng. Bạn có thể thử xóa cuộc gọi đến sse.write khỏi khối with_connection không? – Grasshopper