[英]Redis Subscription + Rails ActionController::Live hangs
[英]mixing redis actioncontroller::live - rails app
我使用的是第一次redis
把聊天功能在我的Rails应用程序,以下这
我的JavaScript中有`
$(document).ready ->
source = new EventSource('/messages/events')
source.addEventListener 'messages.create', (e) ->
message = $.parseJSON(e.data).message
console.log(message)
$(".chat-messages").append "#some code"
在我的消息控制器中
def create
response.headers["Content-Type"] = "text/javascript"
attributes = params.require(:message).permit(:content, :sender_id, :sendee_id)
@message = Message.create(attributes)
respond_to do |format|
format.js { render 'messages/create.js.erb' }
end
$redis.publish('messages.create', @message.to_json)
end
def events
response.headers["Content-Type"] = "text/event-stream"
redis = Redis.new
redis.subscribe('messages.*') do |on|
on.message do |pattern, event, data|
response.stream.write("event: #{event}\n")
response.stream.write("data: #{data}\n\n")
end
end
rescue IOError
logger.info "Stream closed"
ensure
redis.quit
response.stream.close
end
问题是,首先,控制台中未记录任何内容,其次,我得到了一些随机的ConnectionTimeoutError
错误。 有人知道发生了什么事
在config/initializers
目录中创建redis.rb
初始化程序文件,以全球化redis
实例。 设置heartbeat
线也是一个好主意(5秒到5分钟的时间都可以,取决于您的要求):
$redis = Redis.new
heartbeat_thread = Thread.new do
while true
$redis.publish("heartbeat","thump")
sleep 15.seconds
end
end
at_exit do
# not sure this is needed, but just in case
heartbeat_thread.kill
$redis.quit
end
您需要向ChatController
添加pub
和sub
两个方法。 pub
的作用是将聊天事件和消息发布到redis
,并sub
订阅这些事件。 它看起来应该像这样:
class ChatController < ApplicationController
include ActionController::Live
skip_before_filter :verify_authenticity_token
def index
end
def pub
$redis.publish 'chat_event', params[:chat_data].to_json
render json: {}, status: 200
end
def sub
response.headers["Content-Type"] = "text/event-stream"
redis = Redis.new
redis.subscribe(['chat_event']) do |on|
on.message do |event, data|
response.stream.write "event: #{event}\ndata: #{data}\n\n"
end
end
rescue IOError
logger.info "Stream Closed"
ensure
redis.quit
response.stream.close
end
end
在您的routes
,将pub设为POST
并将sub设为GET
,然后将路径匹配到/chat/publish
和/chat/subscribe
。
假设聊天应用程序的实际网页位于/chat
,则需要编写一些Javascript才能实际发送和接收聊天消息。
为了便于理解,我们假设您的网页只有一个文本框和一个按钮。 点击按钮应将文本框的内容发布到聊天流,我们可以使用AJAX做到这一点:
$('button#send').click (e) ->
e.preventDefault()
$.ajax '/chat/publish',
type: 'POST'
data: {
chat_data: {
message: $("input#message").val(),
timestamp: $.now()
}
}
error: (jqXHR, textStatus, errorThrown) ->
console.log "Failed: " + textStatus
success: (data, textStatus, jqXHR) ->
console.log "Success: " + textStatus
现在,您还需要能够订阅和接收聊天消息。 您需要为此使用EventSource
。 使用EventSource ,为SSE打开一个通道,以便您可以接收事件,并使用该数据更新视图。 在此示例中,我们仅将它们记录到javascript控制台。
代码应如下所示:
$(document).ready ->
source = new EventSource('/chat/subscribe')
source.addEventListener 'chat_event', (e) ->
console.log(e.data)
在开发环境中,您必须通过将这两行添加到config/environments/development.rb
来启用并行请求:
config.preload_frameworks = true
config.allow_concurrency = true
现在启动您的浏览器,浏览至/chat
并查看魔术。 当您键入一条消息并单击按钮时,该网页的所有实例都会收到该消息。
好的,这就是使用ActionController::Live
和Redis
在rails
创建基本聊天应用程序的方式。 最终的代码显然会根据您的要求而有很大不同,但这应该可以帮助您入门。
您应该查看更多资源:
尽管我没有以这种身份使用redis
(“实时”数据的中介),但我设法使此功能与Pusher
一起使用
雷迪斯
我不明白您如何保持应用程序和Redis之间的连接打开。 您需要适当的Web套接字或并发连接技术来处理更新-据我所知,Redis不会直接处理此问题。
如果查看此示例 ,它将使用一个名为Goliath的服务器来处理asynchronous
连接:
当mini-chat连接到服务器时,它将向/ subscribe / everyone发送GET请求,每个人都是通道的名称,并且“ Accept”标头设置为text / event-stream。 流中间件(上方)接收此请求并订阅redis发布/订阅通道。 由于Goliath处于非阻塞状态,因此多个客户端可以监听事件而无需占用Heroku dyno。 服务器发送事件的有效负载如下所示:
这基本上是使用中间件将您连接到Redis服务器-允许您根据需要接收更新
码
尽管我无法精确指出任何错误,但可以为您提供一些我们正在使用的代码(使用Pusher ):
#config/initializers/pusher.rb
Pusher.url = ENV["PUSHER_URL"]
Pusher.app_id = ENV["PUSHER_APP_ID"]
Pusher.key = ENV["PUSHER_KEY"]
Pusher.secret = ENV["PUSHER_SECRET"]
#app/controllers/messages_controller.rb
def send_message
id = params[:id]
message = Message.find(id).broadcast!
public_key = self.user.public_key
Pusher['private-user-' + public_key].trigger('message_sent', {
message: "Message Sent"
})
end
#app/views/layouts/application.html.erb
<%= javascript_include_tag "http://js.pusher.com/2.1/pusher.min.js" %>
#app/assets/javascripts/application.js
$(document).ready(function(){
#Pusher
pusher = new Pusher("************",
cluster: 'eu'
)
channel = pusher.subscribe("private-user-#{gon.user}")
channel.bind "multi_destroy", (data) ->
alert data.message
channel.bind "message_sent", (data) ->
alert data.message
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.