[英]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.