问题
我在Redis中有一个名为stocks
的键,它的值是stocks
0.假设300个客户同时请求购买(每个客户购买stocks
只股票).最后,只有10个客户可以购买.
解决方案
我知道它不会起作用,但假设我的buy
函数是这样的:
/**
* @param {import("redis").RedisClientType} instance
* @param {string} clientId
* @param {number} n
*/
async function buy(instance, clientId, n) {
// --- (1) ----
// Get current number of stocks
let stocks = await instance.GET("stocks");
stocks = parseInt(stocks);
// --- (2) ----
// Validate if the stocks remaining are enough to be bought
if (stocks < n) {
console.log("error: company does not have enough stocks");
return new Error("error: company does not have enough stocks");
}
// --- (3) ----
// Update the current stocks of the company and log who has bought stocks
await instance.INCRBY("stocks", -n);
console.log("client @%s has bought %s stocks successfully!", clientId, n);
}
为了测试它,我编写了一个调用buy
函数300次的函数:
const redis = require("redis");
const crypto = require("crypto");
const { buy } = require("./buy");
async function main(customers = 300) {
const instance = await redis
.createClient({ url: "redis://localhost:6379" })
.connect();
// --- (1) ----
// set stocks
await instance.SET("stocks", 1000);
// --- (2) ----
// buy 100 stocks concurrentlly for each customer
let pool = [];
for (let i = 0; i < customers; i++) {
let userId = crypto.randomBytes(4).toString("hex");
pool.push(buy_v3(instance, userId, 100));
}
await Promise.all(pool);
// --- (3) ----
// Get the remaining stocks
let shares = await instance.GET("stocks");
console.log("the number of free shares the company has is: %s", shares);
await instance.disconnect();
}
main();
输出:
...
error: company does not have enough stocks
error: company does not have enough stocks
error: company does not have enough stocks
error: company does not have enough stocks
the number of free stocks the company has is: -29000
正如我所说的,它不起作用,但为了解决这个问题,我使用了以下方法:
/**
* @param {import("redis").RedisClientType} instance
* @param {string} clientId
* @param {number} n
*/
async function buy(instance, clientId, n) {
try {
await instance.executeIsolated(async (client) => {
// --- (1) ----
// Get current number of stocks
let stocks = await client.GET("stocks");
stocks = parseInt(stocks);
// --- (2) ----
// Validate if the stocks remaining are enough to be bought
if (stocks < n) {
throw new Error("error: company does not have enough stocks");
}
// --- (3) ----
// Update the current stocks of the company
await client.INCRBY("stocks", -n);
});
console.log("client @%s has bought %s stocks successfully!", clientId, n);
} catch (err) {
console.log(err.message);
}
}
如果你再次测试它,你会看到类似这样的东西:
...
error: company does not have enough stocks
error: company does not have enough stocks
error: company does not have enough stocks
error: company does not have enough stocks
the number of free stocks the company has is: 0
这意味着它工作起来没有任何问题.
问题
上面的解决方案运行得很好,但我对executeIsolated
函数有点困惑.据我所知,它只是创建一个新的连接(您可以看到here),当您想要在独占连接(如watch
命令)上运行命令时,它很有用.
谁能解释一下,在我的 case 中,executeIsolated
的确切作用是什么?