Ruby и Redis: установите тайм-аут для подписок

Я хотел бы подождать сообщения в канале Redis не более 2 секунд, затем я хочу, чтобы срок действия подписки истек / истекло, и я прекратил блокировать мой код.

redis = Redis.new

redis.subscribe(channel) do |on|
  on.message do |channel, message|
    # ...
  end
end

# This line is never reached if no message is sent to channel :(

Я использую https://github.com/redis/redis-rb. Я искал в источнике, но не нашел вариант тайм-аута для подписок.

3 ответа

Решение

Вы можете добавить блок тайм-аута следующим образом:

require 'timeout'

begin
  Timeout.timeout(2) do      
    redis.subscribe(channel) do |on|
      on.message do |channel, message|
        # ...
      end
    end
  end
rescue Timeout::Error
  # handle error: show user a message?
end

Теперь вы можете подписаться с таймаутом за один шаг:

redis.subscribe_with_timeout(5, channel) do |on|
  on.message do |channel, message|
    # ...
  end
end

В реализации redis-rb pubsub нет опции тайм-аута. Однако это может быть довольно легко с помощью инструментов, которые у вас уже есть:

require 'redis'

channel = 'test'
timeout_channel = 'test_timeout'

timeout = 3

redis = Redis.new

redis.subscribe(channel, time_channel) do |on|
  timeout_at = Time.now + timeout

  on.message do |channel, message|
    redis.unsubscribe if channel == timeout_channel && Time.now >= timeout_at
  end

  # not the best way to do it, but we need something publishing to timeout_channel
  Thread.new {
    sleep timeout
    Redis.new.publish timeout_channel, 'ping'
  }
end

#This line is never reached if no message is sent to channel :(
puts "here we are!"

Основная идея здесь состоит в том, чтобы время от времени публиковать сообщения на отдельном канале. Клиент подписки также подписывается на этот специальный канал и проверяет текущее время, чтобы решить, истек ли он уже.

Другие вопросы по тегам