2016-11-05 2 views
2

Итак, я долгое время изучаю путь JS/Node на других языках.Лучший способ написать простой цикл Node redis (используя ioredis)?

У меня крошечный микросервис, который читается с канала redis, темп сохраняет его на рабочем канале, выполняет работу, удаляет его и перемещается. Если в канале больше, он снова запускается немедленно. Если нет, он устанавливает тайм-аут и снова проверяет через 1 секунду.

Он отлично работает ... но тайм-аут не кажется «правильным» способом приблизиться к этому. И я не нашел много о том, как использовать BRPOPLPUSH, чтобы попытаться заблокировать (против RPOPLPUSH) и подождать в узле .... или другие варианты. (Pub/Sub не является вариантом здесь ... это единственный слушатель, и это не всегда может слушать.)

Вот короткая суть того, что я делаю:

var Redis = require('ioredis'); 
var redis = new Redis(); 

var redisLoop = function() { 
    redis.rpoplpush('channel', 'channel-working').then(function (result) { 
     if (result) { 
      processJob(result); //do stuff 

      //delete the item from the working channel, and check for another item 
      redis.lrem('channel-working', 1, result).then(function (result) { }); 
      redisLoop(); 
     } else { 
      //no items, wait 1 second and try again 
      setTimeout(redisLoop, 1000); 
     } 
    }); 
}; 

redisLoop(); 

Я чувствую, что мне не хватает чего-то действительно очевидного. Благодаря!

+0

Можете ли вы рассказать о том, почему pub/sub не является вариантом? Прекрасно публиковать, когда подписчиков не подписывают. У вас будет процесс, который подталкивает работу в Redis, также публикует. Если это приложение подписано, оно разбудит его. Если нет, ничего не происходит. –

+0

Из того, что я видел (без более сложных обходных решений), если сообщение опубликовано без подписчиков, сообщение теряется. Это скорее модель очереди сообщений, и только один слушатель - самое главное, что элементы в канале сидят без дела до тех пор, пока не появятся эти секунды или дни (если процесс замирает, машина переходит в автономный режим и т. Д.). – XediDC

+0

Это правда, сообщение потеряно. Вот почему вы * также * публикуете: приложение, создающее работу, помещает работу в очередь и только затем «ПУБЛИКУ» что-то (скажем, пустую строку), чтобы это приложение просыпалось, если оно в сети, но сон. –

ответ

2

BRPOPLPUSH не блокирует в Node, он блокирует в клиента. В этом случае я думаю, что это именно то, что вам нужно, чтобы избавиться от опроса.

var Redis = require('ioredis'); 
var redis = new Redis(); 

var redisLoop = function() { 
    redis.brpoplpush('channel', 'channel-working', 0).then(function (result) { 
     // because we are using BRPOPLPUSH, the client promise will not resolve 
     // until a 'result' becomes available 
     processJob(result); 

     // delete the item from the working channel, and check for another item 
     redis.lrem('channel-working', 1, result).then(redisLoop); 
    }); 
}; 

redisLoop(); 

Обратите внимание, что redis.lrem асинхронный, так что вы должны использовать lrem(...).then(redisLoop), чтобы убедиться, что ваш следующий тик выполняется только после того, как элемент успешно удален из channel-working.

+0

Спасибо! Я думаю, что, возможно, подошел близко к этому ... но затем пошел в другом направлении, прежде чем я добрался туда. Сейчас выглядит очень очевидно, глядя на мой урезанный пример, а затем на то, что вы написали. :) – XediDC

+0

Да, это сработало отлично. Еще раз спасибо! – XediDC

+0

Нет проблем! Кстати, важно, чтобы ни один I/O не блокировал в узле здесь. Вы можете выполнять другую работу одновременно. Однако, если вы пытаетесь повторно использовать один и тот же клиент «redis» для одновременного вызова Redis, тогда ваш цикл _will_ вмешивается. Я упоминаю, потому что это немного меня в недавнем проекте, и я понял, что мне нужен второй «неблокирующий» клиент для запуска команд, в то время как первый из них блокируется. –

Смежные вопросы