Rails & ActionCable 本地主机上的网络请求时间为 1.8 小时/Heroku 上的高响应时间
Rails & ActionCable 1.8hr network request time on localhost / High Response Time on Heroku
Chrome 中的“网络”选项卡显示 /cable
请求在本地主机上的 小时 秒和 小时之间波动:
...然后是 "pending" 请求的疯狂多米诺骨牌堆栈:
在带有 Puma 服务器和 512 MB dyno 的 Heroku 上,我在 /cable
端点上收到高响应时间警告。这是日志条目的示例:
25 Dec 2019 14:13:31.061299 <158>1 2019-12-25T22:13:28.421009+00:00 heroku router - - at=info method=GET path="/cable" host=www.######.com request_id=#### fwd="####" dyno=web.1 connect=1ms service=531114ms status=101 bytes=174 protocol=https High Response Time
在所有情况下,我都是唯一使用该应用程序的人。我已经看到最多 3-4 个其他人在使用 ActionCable 时遇到过这个问题,但是 none 他们中似乎有任何解决方案,我束手无策。我研究过 AnyCable 和 Iodine,但 AnyCable 不工作,Iodine 也没有解决我的问题。还有什么可能导致这种情况?
预期行为: /cable
请求应在几毫秒内处理。
实际行为: 一些 /cable
请求在 80 年后得到处理,然后数百个其他请求陷入 pending
状态。
系统配置:Ruby版本:2.5.0,Rails版本:5.2.0,Puma版本:4.3.1
channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.username
end
protected
def find_verified_user
if verified_user = User.find_by(id: cookies.signed['user.id'])
verified_user
else
reject_unauthorized_connection
end
end
end
end
channels/messages_channel.rb
class MessagesChannel < ApplicationCable::Channel
def subscribed
stream_from "user_#{current_user.id}_messages_channel"
end
def unsubscribed
stop_all_streams
end
def speak(data)
Message.create! body: data['message'], conversation_id: data['conversation_id'], user_id: current_user.id
end
end
javascripts/channels/messages.咖啡
App.messages = App.cable.subscriptions.create "MessagesChannel",
connected: ->
console.log 'Connected'
disconnected: ->
console.log 'Disconnected'
received: (data) ->
console.log 'Received'
$("[data-conversation-id='" + data.conversation_id + "']").append(data.message)
console.log 'Received'
$("#messages").append(data.message)
speak: (message, conversation_id) ->
@perform 'speak', message: message, conversation_id: conversation_id
$(document).on 'turbolinks:load', ->
submit_message()
scroll_bottom()
submit_message = () ->
$('#response').on 'keydown', (event) ->
if event.keyCode is 13
message = event.target.value
conversation_id = $("#messages").data("conversation-id")
App.messages.speak(message, conversation_id)
event.target.value = ""
event.preventDefault()
scroll_bottom = () ->
if $('#messages').length > 0
$('#messages').scrollTop($('#messages')[0].scrollHeight)
models/messages.rb
class Message < ApplicationRecord
after_create_commit { MessageBroadcastWorker.perform_async self.id }
end
workers/message_broadcast_worker.rb
class MessageBroadcastWorker
include Sidekiq::Worker
def perform(message_id)
message = Message.find message_id
user = message.user
ActionCable.server.broadcast("user_#{user.id}_messages_channel", message: render_message(message, user))
end
private
def render_message(message, user)
ApplicationController.renderer.render(partial: 'messages/message', locals: { message: message, user: user })
end
end
解决方案是关闭 Heroku 日志的警报。 /cable
请求 不是 轮询服务器以获取更新,它建立单个请求然后 保持打开状态 直到用户注销或离开网站。
Chrome 中的“网络”选项卡显示 /cable
请求在本地主机上的 小时 秒和 小时之间波动:
...然后是 "pending" 请求的疯狂多米诺骨牌堆栈:
在带有 Puma 服务器和 512 MB dyno 的 Heroku 上,我在 /cable
端点上收到高响应时间警告。这是日志条目的示例:
25 Dec 2019 14:13:31.061299 <158>1 2019-12-25T22:13:28.421009+00:00 heroku router - - at=info method=GET path="/cable" host=www.######.com request_id=#### fwd="####" dyno=web.1 connect=1ms service=531114ms status=101 bytes=174 protocol=https High Response Time
在所有情况下,我都是唯一使用该应用程序的人。我已经看到最多 3-4 个其他人在使用 ActionCable 时遇到过这个问题,但是 none 他们中似乎有任何解决方案,我束手无策。我研究过 AnyCable 和 Iodine,但 AnyCable 不工作,Iodine 也没有解决我的问题。还有什么可能导致这种情况?
预期行为: /cable
请求应在几毫秒内处理。
实际行为: 一些 /cable
请求在 80 年后得到处理,然后数百个其他请求陷入 pending
状态。
系统配置:Ruby版本:2.5.0,Rails版本:5.2.0,Puma版本:4.3.1
channels/application_cable/channel.rb
module ApplicationCable
class Channel < ActionCable::Channel::Base
end
end
channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.username
end
protected
def find_verified_user
if verified_user = User.find_by(id: cookies.signed['user.id'])
verified_user
else
reject_unauthorized_connection
end
end
end
end
channels/messages_channel.rb
class MessagesChannel < ApplicationCable::Channel
def subscribed
stream_from "user_#{current_user.id}_messages_channel"
end
def unsubscribed
stop_all_streams
end
def speak(data)
Message.create! body: data['message'], conversation_id: data['conversation_id'], user_id: current_user.id
end
end
javascripts/channels/messages.咖啡
App.messages = App.cable.subscriptions.create "MessagesChannel",
connected: ->
console.log 'Connected'
disconnected: ->
console.log 'Disconnected'
received: (data) ->
console.log 'Received'
$("[data-conversation-id='" + data.conversation_id + "']").append(data.message)
console.log 'Received'
$("#messages").append(data.message)
speak: (message, conversation_id) ->
@perform 'speak', message: message, conversation_id: conversation_id
$(document).on 'turbolinks:load', ->
submit_message()
scroll_bottom()
submit_message = () ->
$('#response').on 'keydown', (event) ->
if event.keyCode is 13
message = event.target.value
conversation_id = $("#messages").data("conversation-id")
App.messages.speak(message, conversation_id)
event.target.value = ""
event.preventDefault()
scroll_bottom = () ->
if $('#messages').length > 0
$('#messages').scrollTop($('#messages')[0].scrollHeight)
models/messages.rb
class Message < ApplicationRecord
after_create_commit { MessageBroadcastWorker.perform_async self.id }
end
workers/message_broadcast_worker.rb
class MessageBroadcastWorker
include Sidekiq::Worker
def perform(message_id)
message = Message.find message_id
user = message.user
ActionCable.server.broadcast("user_#{user.id}_messages_channel", message: render_message(message, user))
end
private
def render_message(message, user)
ApplicationController.renderer.render(partial: 'messages/message', locals: { message: message, user: user })
end
end
解决方案是关闭 Heroku 日志的警报。 /cable
请求 不是 轮询服务器以获取更新,它建立单个请求然后 保持打开状态 直到用户注销或离开网站。