简体   繁体   English

混合redis actioncontroller :: live-Rails应用

[英]mixing redis actioncontroller::live - rails app

I am using for the first time redis to put chat functionality in my rails app, following this 我使用的是第一次redis把聊天功能在我的Rails应用程序,以下

I have in my javascript` 我的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"

and in my message controller 在我的消息控制器中

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

The problem is that first, nothing is logged in my console, and second I get numbers of random ConnectionTimeoutError errors. 问题是,首先,控制台中未记录任何内容,其次,我得到了一些随机的ConnectionTimeoutError错误。 Some one hava an idea what's going on 有人知道发生了什么事

Pre-Reqs: 先决条件:

  • Ruby 2.0.0+ Ruby 2.0.0+
  • Rails 4.0.0+ Rails 4.0.0+
  • Redis 雷迪斯
  • Puma 彪马

Initializer: 初始化器:

Create a redis.rb initializer file in the config/initializers directory, globalizing an instance of redis . config/initializers目录中创建redis.rb初始化程序文件,以全球化redis实例。 It's also a good idea to set up a heartbeat thread (Anything from 5 seconds to 5 minutes is okay, depending on your requirements): 设置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

Controller: 控制器:

You need to add two methods to your ChatController , pub and sub . 您需要向ChatController添加pubsub两个方法。 The role of pub is to publish chat events and messages to redis , and sub to subscribe to these events. pub的作用是将聊天事件和消息发布到redis ,并sub订阅这些事件。 It should look something like this: 它看起来应该像这样:

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

In your routes , make pub a POST and sub a GET , and match the path to something like /chat/publish and /chat/subscribe . 在您的routes ,将pub设为POST并将sub设为GET ,然后将路径匹配到/chat/publish/chat/subscribe


Coffeescript / Javascript: Coffeescript / Javascript:

Assuming your actual webpage for the chat app is at /chat , you need to write some Javascript to actually send and receive chat messages. 假设聊天应用程序的实际网页位于/chat ,则需要编写一些Javascript才能实际发送和接收聊天消息。

For ease of understanding, let's suppose your webpage only has a textbox and a button. 为了便于理解,我们假设您的网页只有一个文本框和一个按钮。 Hitting the button should publish the content of the textbox to the chat stream, we can do that using AJAX: 点击按钮应将文本框的内容发布到聊天流,我们可以使用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

Now, you need to be able to subscribe and receive the chat messages as well. 现在,您还需要能够订阅和接收聊天消息。 You need to use EventSource for this. 您需要为此使用EventSource Using EventSource , open a channel for SSE so that you can receive events, and use that data to update the view. 使用EventSource ,为SSE打开一个通道,以便您可以接收事件,并使用该数据更新视图。 In this example, we will only log them to the javascript console. 在此示例中,我们仅将它们记录到javascript控制台。

The code should look something like this: 代码应如下所示:

$(document).ready ->
    source = new EventSource('/chat/subscribe')
    source.addEventListener 'chat_event', (e) ->
        console.log(e.data)

Enable Parallel Requests: 启用并行请求:

In your development environment, you'll have to enable parallel requests by adding these two lines to your config/environments/development.rb : 在开发环境中,您必须通过将这两行添加到config/environments/development.rb来启用并行请求:

config.preload_frameworks = true
config.allow_concurrency = true

Now fire up your browser, browse to /chat and see the magic. 现在启动您的浏览器,浏览至/chat并查看魔术。 When you type a message and click the button, the message will be received by all instances of that webpage. 当您键入一条消息并单击按钮时,该网页的所有实例都会收到该消息。


Well this is how you make a basic chat application in rails using ActionController::Live and Redis . 好的,这就是使用ActionController::LiveRedisrails创建基本聊天应用程序的方式。 The final code would obviously be very different depending on your requirements but this should get you started. 最终的代码显然会根据您的要求而有很大不同,但这应该可以帮助您入门。

Some more resources you should check out: 您应该查看更多资源:

Although I've not used redis in this capacity (a mediator for "live" data), I managed to get this functionality working with Pusher 尽管我没有以这种身份使用redis (“实时”数据的中介),但我设法使此功能与Pusher一起使用


Redis 雷迪斯

I don't understand how you're keeping the connection open between your app & Redis. 我不明白您如何保持应用程序和Redis之间的连接打开。 You'll need some sort of web socket or concurrent-connection tech in place to handle the updates -- and to my knowledge, Redis does not handle this directly 您需要适当的Web套接字或并发连接技术来处理更新-据我所知,Redis不会直接处理此问题。

If you look at this example , it uses a server called Goliath to handle the asynchronous connectivity: 如果查看此示例 ,它将使用一个名为Goliath的服务器来处理asynchronous连接:

When tiny-chat connects to the server it sends a GET request to /subscribe/everyone where everyone is the name of the channel and with the “Accept” header set to text/event-stream. 当mini-chat连接到服务器时,它将向/ subscribe / everyone发送GET请求,每个人都是通道的名称,并且“ Accept”标头设置为text / event-stream。 The streaming middleware (above) receives this request and subscribes to a redis Pub/Sub channel. 流中间件(上方)接收此请求并订阅redis发布/订阅通道。 Since Goliath is non-blocking multiple clients can be listening for events without tying up a Heroku dyno. 由于Goliath处于非阻塞状态,因此多个客户端可以监听事件而无需占用Heroku dyno。 The payload of a server sent event looks like this: 服务器发送事件的有效负载如下所示:

That basically uses Middleware to connect you to the redis server -- allowing you to receive updates as required 这基本上是使用中间件将您连接到Redis服务器-允许您根据需要接收更新


Code

Although I can't pinpoint any errors specifically, I can give you some code we're using (using Pusher ): 尽管我无法精确指出任何错误,但可以为您提供一些我们正在使用的代码(使用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.

相关问题 Redis订阅+ Rails ActionController :: Live挂起 - Redis Subscription + Rails ActionController::Live hangs ActionController :: Live - Rails中的SSE - ActionController::Live - SSE in Rails Redis + ActionController::活动线程没有死 - Redis + ActionController::Live threads not dying Rails,ActionController :: Live,Puma:ThreadError - Rails, ActionController::Live, Puma: ThreadError Rails ActionController :: Live连接被删除 - Rails ActionController::Live connection dropped Rails ActionController :: Live在开发时无需重启服务器 - Rails ActionController::Live without restart server on developpement 如何使用ActionController :: Live以及Resque + Redis(用于聊天应用程序) - How to use ActionController::Live along with Resque + Redis (for Chat application) 我的 rails 应用程序中的随机 ActionController::InvalidAuthenticityToken - random ActionController::InvalidAuthenticityToken in my rails app Rails ActionController :: Live-一次发送所有内容,而不是异步 - Rails ActionController::Live - Sends everything at once instead of async ActionController :: InvalidAuthenticityToken(ActionController :: InvalidAuthenticityToken):Rails 5 - ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): Rails 5
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM