javascript - 如何保证邀请码在Redis中是唯一的

标签 javascript node.js redis node-redis

我需要生成一个独特的用户友好代码并将其保存到 Redis 中,直到受邀用户对其进行评分或过期。 由于代码必须用户友好,我决定使用 6 位数字,前端会将其分成两组,例如xxx-xxx.

现在,在后端,我有 NodeJS 和 node_redis。 这就是我生成随机字符串并将其保存到 Redis 中的方式:

    var invCode = Math.floor(Math.random() * 90000) + 100000;
    var key = "invitation-code:" + invCode;
    const TTL = 3 * 24 * 60 * 60; // 3 days

    redis.client.existsAsync(key)
        .then(res => {
            if (!res) {
                // ok, I can add the key, value pair
                return redis.client.setAsync(key, value, 'EX', TTL);
            } else {
                // I have to generate new key and check it again
                // how can I re-iterate the process???
                return null;
            }
        })
        .then(res => {
            logger.info('InvitationCodeController::generate added <' + key + ', ' + value + '> pair');
        })
        .catch(error => {
            logger.error('InvitationCodeController::generate Error ' + error);
        });

现在,我想不通的一点是——如果生成的代码已经存在,我该如何重新迭代这个过程,即生成另一个随机字符串、格式化它、 checkin Redis 等等。 由于我有异步调用,我认为任何类型的循环都不适合我?

有什么想法吗?

最佳答案

您可以使用如下所示的“尝试”过程。 您也可以通过删除 --n 部分来类似地创建一个 while 循环。

此外,我认为您应该为“SETNX”使用“NX”参数——当值不存在时设置。否则有可能在你检查redis的key是否存在的时间和你实际设置它的时间之间,你可以覆盖一些其他的key。此时您甚至可以重写它,因此依赖于 SETNX 在设置失败时抛出错误,而不是每次都检查值。

const process = require('process');
const redis = require("redis");
const Bluebird = require('bluebird')
Bluebird.promisifyAll(redis.RedisClient.prototype)
Bluebird.promisifyAll(redis.Multi.prototype)
const winston = require('winston');
const logger = winston.createLogger({
  level: 'silly',
  format: winston.format.json(),
  transports: [new winston.transports.Console({
    format: winston.format.simple()
  })]
});

const client = redis.createClient({
  host:'redis-19141.c16.us-east-1-3.ec2.cloud.redislabs.com',
  port:'19141'
});
client.auth('I6C2ISvac4suTbxSYcbsjWiz635NK8Wv');
// client.set("string key", "string val", redis.print);

var invCode = Math.floor(Math.random() * 90000) + 100000;
// test invCode being the same --- retry.
invCode = 111111;
var key = "invitation-code:" + invCode;
const TTL = 3 * 24 * 60 * 60; // 3 days

let value = "test";
const trySet = function(key,n){
  const used = process.memoryUsage().heapUsed / 1024 / 1024;
  logger.info(`The script uses approximately ${Math.round(used * 100) / 100} MB`);
  return client.existsAsync(key)
  .then(res => {
    logger.info("existsAsync res",res);
    if (!res) {
      logger.info("Key does not exist!");
      return client.setAsync(key, value, 'NX','EX', TTL) 
        .then(res => {
          logger.info('InvitationCodeController::generate added <' + key + ', ' + value + '> pair');
          return true;
        })
    } else {
      logger.info("Key already exists!");
      if(n > 0){
        return trySet(key,--n);
      }else{
        return false;
      }
    }
  })
  .catch(error => {
    logger.error('InvitationCodeController::generate Error ' + error);
    return false;
  });
}

trySet(key,50).then(function(res){
  if(res){
    logger.info('trySet::success');
  }else{
    logger.info('trySet::failed');
  }
}).catch(error => {
  logger.error('trySet::error');
});

https://repl.it/repls/ImmediateSufficientCoin

关于javascript - 如何保证邀请码在Redis中是唯一的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51966660/

相关文章:

javascript - 返回事件处理函数

javascript - 路径中每个节点的CSS选择器

redis - 停止 redis 服务器。既不关机也不停止工作

docker - 无法从主机连接到在自定义端口上的 Docker 容器内运行的 Redis

javascript - 如何验证 ionic 单选按钮

javascript - 如何让按钮在 F 和 C 之间切换?

node.js - stomp.ack 产生错误 : Unexpected ACK received for message-id

node.js - 无法卸载 NVM 包

javascript - 我怎样才能包装这个特定的函数?

Node.js rsmq - 在重新启动 Node.js 应用程序之前,新消息不会变得可见