QA@IT
«質問へ戻る

質問を投稿

redis-rb で subscribe 中にブロック外から subscribe 先の追加

イメージとしてはこういう事がしたいんですが、 (現状は synchronize でブロックされる。最初に Redis#subscribe に渡したブロック内だとブロックされない)

redis = Redis.new
Thread.new do
  redis.subscribe do |on|
    on.message {|ch, msg| p [ch, msg] }
  end
end
redis.subscribe("a")
Redis.new.publish("a", "hello")
redis.unsubscribe("a")
Redis.new.publish("a", "bye")
#=> ["a", "hello"]

こういう方法しかないんでしょうか:

require 'redis'

th = Thread.new(Redis.new) do |redis|
  loop do
    redis.publish('time', Time.now.to_s)
    sleep 1
  end
end

# Redis client for subscription
sub_redis = Redis.new
class << sub_redis
  def subscribe_add(*channels)
    client.instance_variable_get(:@client).write([["SUBSCRIBE", *channels.map(&:to_s)]])
  end

  def subscribe_rem(*channels)
    client.instance_variable_get(:@client).write([["UNSUBSCRIBE", *channels.map(&:to_s)]])
  end
end

sub_redis_ready = false

subscription_thread = Thread.new do
  sub_redis.subscribe("dummy") do |on|
    on.subscribe do
      sub_redis_ready = true
    end

    on.message do |ch, msg|
      p [ch, msg]
    end
  end
end

nil until sub_redis_ready
sub_redis.subscribe_add('time')
sleep 10
sub_redis.subscribe_rem('time')
th.join

綺麗な方法があれば教えてください。

イメージとしてはこういう事がしたいんですが、 (現状は synchronize でブロックされる。最初に `Redis#subscribe` に渡したブロック内だとブロックされない)

``` ruby
redis = Redis.new
Thread.new do
  redis.subscribe do |on|
    on.message {|ch, msg| p [ch, msg] }
  end
end
redis.subscribe("a")
Redis.new.publish("a", "hello")
redis.unsubscribe("a")
Redis.new.publish("a", "bye")
#=> ["a", "hello"]
```

こういう方法しかないんでしょうか:

``` ruby
require 'redis'

th = Thread.new(Redis.new) do |redis|
  loop do
    redis.publish('time', Time.now.to_s)
    sleep 1
  end
end

# Redis client for subscription
sub_redis = Redis.new
class << sub_redis
  def subscribe_add(*channels)
    client.instance_variable_get(:@client).write([["SUBSCRIBE", *channels.map(&:to_s)]])
  end

  def subscribe_rem(*channels)
    client.instance_variable_get(:@client).write([["UNSUBSCRIBE", *channels.map(&:to_s)]])
  end
end

sub_redis_ready = false

subscription_thread = Thread.new do
  sub_redis.subscribe("dummy") do |on|
    on.subscribe do
      sub_redis_ready = true
    end

    on.message do |ch, msg|
      p [ch, msg]
    end
  end
end

nil until sub_redis_ready
sub_redis.subscribe_add('time')
sleep 10
sub_redis.subscribe_rem('time')
th.join
```

綺麗な方法があれば教えてください。