【问题标题】:Node.js check value in a few redis sets and return synchronouslyNode.js检查几个redis集合中的值并同步返回
【发布时间】:2017-01-19 20:35:07
【问题描述】:

我有 7 个集合,我需要检查至少一个集合中是否存在值 (sismember) 并返回 true 或 false。

我需要同步获取该值,如下所示:

const isExist = !!(_.max(_.range(7).map((day) => {
    redis.sismember(`blacklist${day}`, hashToken, function (err, res) {
       return res;
    });
})));

【问题讨论】:

  • 您可以使用 lua 脚本运行查询 redis 端吗?
  • @ChrisTanner 不,抱歉,我不能。我需要在 node.js 服务器上做。
  • 与其做 7 次往返 redis,不如考虑使用 lua 脚本,它可以原子地执行此操作。这样您就可以确保您的检查操作不会被任何其他客户端代码中断。
  • 可以写一个lua脚本,通过nodeJS调用。

标签: javascript node.js asynchronous redis node-redis


【解决方案1】:

当你可以避免同步代码时,你永远不会想要它。

在这种情况下,我建议使用 Promises 来管理对 redis 的七个请求。

Bluebird promise library 可以在一行代码中实现大多数 API 的 promise-compatible(阅读 promisification),redis 的 API 也不例外。 (Bluebird 的文档甚至是 uses redis as an examplenode-redis documentation 也是如此,所以它甚至是“官方支持的”,如果你喜欢这种东西的话。)

因此,您似乎想要一个函数,该函数最多可检查对 sismember 的七个异步调用,并在其中第一个得到肯定结果时立即解析为总体肯定结果 - Promise#any() 可以做到这一点。

var Promise = require('bluebird');
var _ = require('lodash');
var redis = require('redis');

Promise.promisifyAll(redis);

function checkBlacklist(hashToken) {
    var blacklistChecks = _.range(7).map((day) => {
        return redis.sismemberAsync(`blacklist${day}`, hashToken);
    });
    return Promise.any(blacklistChecks);
}

用法

checkBlacklist('some_token').then((result) => {
   // do something with the result
}).catch((err) => {
   // an error has occurred - handle it or rethrow it
});

【讨论】:

    【解决方案2】:

    如果涉及多个redis ops,一般我更喜欢写lua脚本,然后通过我的nodejs程序调用。这是一个不相关的例子,但它展示了如何通过 nodejs 使用 lua。

    示例:get_state.lua

    local jobId = KEYS[1]
    local jobExists = redis.pcall('exists', jobId)
    if jobExists == 0 or jobExists == nil then
      return 404  -- not found.
    end
    
    -- check the job state
    local st = tonumber(redis.pcall('hmget', jobId, 'ctlState')[1])
    if st == nil then
      st = 12002  -- job running, unless explicitly stated otherwise
    end
    return st
    

    使用 lua 的 NodeJS 代码:比如 index.js

    ...
    // List of script files 
    var scriptMap = { 
      getState: {file:'./scripts/get_state.lua'}
    };
    
    
    ...
    
    // A function to load the script file to Redis and cache the sha.
    function loadScript(script) {
      logger.trace("loadScript(): executing...");
      if (scriptMap[script]['hash']) {
        logger.trace("Sript already loaded. Returning without loading again...");
        return Promise.resolve(scriptMap[script]['hash']);
      }
    
      //load from file and send to redis
      logger.trace("Loading script from file %s...", scriptMap[script].file);
      return fs.readFileAsync(scriptMap[script].file).then(function(data) {
        return getConnection().then(function(conn) {
          logger.trace("Loading script to Redis...");
          return conn.scriptAsync('load', data)
        })
      })
    }
    

    最后,还有一个使用缓存的 sha 摘要来执行脚本的函数:

    getJobState: function(jobId) {
        return loadScript('getState').then(function(hash) {
          return getConnection().then(function (conn) {
            return conn.evalshaAsync(hash, 1, jobId)
          })
        })
      },
    

    【讨论】:

      猜你喜欢
      • 2016-06-02
      • 2012-07-03
      • 2018-01-30
      • 2016-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      相关资源
      最近更新 更多