使用em-synchrony,抽取框架同步“渲染”正确的方式

时间:2013-10-31 20:41:43

标签: ruby eventmachine em-synchrony cramp

为了描述我的问题,我附上了简单的Cramp http://cramp.in/类。 我添加了一些修改,但其主要工作类似于https://github.com/lifo/cramp-pub-sub-chat-demo/blob/master/app/actions/chat_action.rb

class ChatAction < Cramp::Websocket

  use_fiber_pool

  on_start :create_redis
  on_finish :handle_leave, :destroy_redis
  on_data :received_data

  def create_redis
    @redis = EM::Hiredis.connect('redis://127.0.0.1:6379/0')    
  end

  def destroy_redis
    @redis.pubsub.close_connection
    @redis.close_connection
  end

  def received_data(data)
    msg = parse_json(data)
    case msg[:action]
    when 'join'
      handle_join(msg)
    when 'message'
      handle_message(msg)
    else
      # skip
    end
  end

  def handle_join(msg)
    @user = msg[:user]
    subscribe
    publish(:action => 'control', :user => @user, :message => 'joined the chat room')
  end

  def handle_leave
    publish :action => 'control', :user => @user, :message => 'left the chat room'
  end

  def handle_message(msg)
    publish(msg.merge(:user => @user))
    # added only for inline sync tests
    render_json(:action => 'message', :user => @user, :message => "this info should appear after published message")
  end

  private

  def subscribe
    @redis.pubsub.subscribe('chat') do |message|
      render(message)
    end
  end

  def publish(message)
    @redis.publish('chat', encode_json(message))
  end

  def encode_json(obj)
    Yajl::Encoder.encode(obj)
  end

  def parse_json(str)
    Yajl::Parser.parse(str, :symbolize_keys => true)
  end

  def render_json(hash)
    render encode_json(hash)
  end
end

更多关于我尝试做的是handle_message方法。

我尝试以正确的顺序向客户端发送消息。首先向所有订户发布消息,然后仅为当前连接的客户端呈现一些内部信息。

对于上面的代码客户端收到:

{"action":"message","user":"user1","message":"this info should appear after published message"}
{"action":"message","message":"simple message","user":"user1"}

它可能不是同步的,因为em-hiredis可以反对。 所以我尝试以这种方式同步它:

def handle_message(msg)
  EM::Synchrony.sync publish(msg.merge(:user => @user))
  EM::Synchrony.next_tick do # if I comment this block messages order is still incorrect
     render_json(:action => 'message', :user => @user, :message => "this info should appear after published message")
  end
end

现在,客户端处理正确顺序的消息。

{"action":"message","message":"simple message","user":"user1"}
{"action":"message","user":"user1","message":"this info should appear after published message"}

我的问题是:

  • 当我评论EM :: Synchrony.next_tick块时,消息顺序仍然不正确。在这个例子中有什么含义EM :: Synchrony.next_tick块?
  • 这是处理与Cramp或EventMachine内联同步的好方法吗?
  • 是否有更好,更清晰的方法来处理它?<​​/ li>

谢谢!

1 个答案:

答案 0 :(得分:0)

我找到了这个问题的解决方案,通过要求这个库,em-synchrony应该开箱即用:

require 'em-synchrony/em-hiredis'

class ChatAction < Cramp::Websocket

使用EM :: Synchrony.next_tick块是个坏主意,在em-synchrony社区的帮助下我添加了em-hiredis 0.2.1 compatibility patch on github

所以现在handle_message方法如下所示:

def handle_message(msg)
   publish(msg.merge(:user => @user))
   render_json(:action => 'message', :user => @user, :message => "this info should appear after published message")
end

不要忘记从github拿这个宝石

gem 'em-synchrony', :git=> 'git://github.com/igrigorik/em-synchrony.git'

希望它有所帮助。