0

为了描述我的问题,我附上了简单的 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 处理内联同步的好方法吗?
  • 有没有更好、更清晰的方法来处理它?

谢谢!

4

1 回答 1

0

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

require 'em-synchrony/em-hiredis'

class ChatAction < Cramp::Websocket

使用 EM::Synchrony.next_tick 块是个坏主意,在 em-synchrony 社区的大力帮助下,我在 github 上添加了 em-hiredis 0.2.1 兼容性补丁

所以现在 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

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

希望它可以帮助某人。

于 2013-11-12T23:08:07.540 回答