我需要生成一个唯一的用户友好代码,并将其保存到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);
});
现在,我无法弄清楚的是-如果生成的代码已经存在,我如何再次重复该过程,即生成另一个随机字符串,对其进行格式化,签入Redis等。 由于我有一个异步调用,因此我认为没有任何一种循环对我有用吗?
有什么想法吗?
答案 0 :(得分:1)
您可以利用如下的“尝试”过程。
您也可以通过删除--n
部分来类似地进行while循环。
此外,我认为您应该对“ SETNX”使用“ NX”参数---当该值不存在时设置。否则,有可能在您检查redis密钥是否存在与实际设置密钥之间,您可能会覆盖其他密钥。您甚至可能会在此时重写它,因此请依靠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');
});
答案 1 :(得分:0)
由于代码生成是同步过程,所以我知道,我可以用其他方法来实现。这是代码:
const TTL = 3 * 24 * 60 * 60; // 3 days
var invCode = '';
const pattern = "invitation-code:";
var prepKey = '';
redis.client.keysAsync(pattern + "*")
.then(keys => {
// these are all keys / invitation codes
var isFound = false;
do {
invCode = Math.floor(Math.random() * 90000) + 100000;
prepKey = pattern + invCode;
// traverse keys to check if the invitation code matches
keys.forEach(key => {
if (key === prepKey) {
isFound = true;
}
});
} while (isFound);
return prepKey;
})
.then(key => {
return redis.client.setAsync(key, value, 'EX', TTL);
})
.then(res => {
logger.info('InvitationCodeController::generate added <' + prepKey + ', ' + value + '> pair');
})
.catch(error => {
logger.error('InvitationCodeController::generate Error ' + error);
});
希望这对其他人有帮助...