问题:
前端页面发出x个并行请求(我们称之为第一组(,下一组(x请求(将在5秒后,(第一组的(第一个请求从DB设置缓存。其他x-1请求得到了空数组,而不是等待第一个请求完成他的工作。第二组和接下来的所有请求都从缓存中获得了正确的数据。
在无状态机制中,锁定其他线程直到第一次完成(或失败(的最佳实践是什么?
编辑:
缓存模块允许使用set-chache的触发器,但由于它是无状态机制,所以不起作用。
const GetDataFromDB= async (req, res, next) => {
var cachedTableName = undefined;
// "lockFlag" uses to prevent parallel request to get into critical section (because its take time to set cache from db)
// to prevent that we uses "lockFlag" that is short-initiation to cache.
//
if ( !myCache.has( "lockFlag" ) && !myCache.has( "dbtable" ) ){
// here arrive first req from first group only
// the other x-1 of first group went to the nest condition
// here i would build mechanism to wait 'till first req come back from DB (init cache)
myCache.set( "lockFlag", "1" )
const connection1 = await odbc.connect(connectionConfig);
const cachedTableName = await connection1.query(`select * from ${tableName}`);
if(cachedTableName.length){
const success = myCache.set([
{key: "dbtable", val: cachedTableName, ttl: 180},
])
if(success)
{
cachedTableName = myCache.get( "dbtable" );
}
}
myCache.take("lockFlag");
connection1.close();
return res.status(200).json(cachedTableName ); // uses for first response.
}
// here comes x-1 of first group went to the nest condition and got nothing, bacause the cache not set yet
//
if ( myCache.has( "dbtable" ) ){
cachedTableName = myCache.get( "dbtable" );
}
return res.status(200).json(cachedTableName );
}
您可以尝试这里给出的方法,并进行一些小的修改以将其应用于您的案例。
- 为了简洁起见,我删除了注释并缩短了变量名
代码,然后解释:
const EventEmitter = require('events');
const bus = new EventEmitter();
const getDataFromDB = async (req, res, next) => {
var table = undefined;
if (myCache.has("lockFlag")) {
await new Promise(resolve => bus.once("unlocked", resolve));
}
if (myCache.has("dbtable")) {
table = myCache.get("dbtable");
}
else {
myCache.set("lockFlag", "1");
const connection = await odbc.connect(connectionConfig);
table = await connection.query(`select * from ${tableName}`);
connection.close();
if (table.length) {
const success = myCache.set([
{ key: "dbtable", val: table, ttl: 180 },
]);
}
myCache.take("lockFlag");
bus.emit("unlocked");
}
return res.status(200).json(table);
}
这就是它应该如何工作:
- 起初,
lockFlag
不存在 - 然后,一些代码调用
getDataFromDB
。该代码将第一个if
块求值为false,因此它继续:它将lockFlag
设置为true("1"
(,然后继续从数据库检索表数据。同时: - 其他一些代码调用
getDataFromDB
。然而,该代码将第一个if
块求值为true,因此它等待promise,直到发出unlocked
事件 - 回到第一个调用代码:它完成逻辑,缓存表数据,将
lockFlag
设置回false,发出unlocked
事件,然后返回 - 另一个代码现在可以继续执行:它将第二个
if
求值为true,因此它从缓存中获取表并返回
作为解决方法,我添加了"最后";第一次启动后从缓存中删除锁定密钥的范围,这是:
while(myCache.has( "lockFlag" )){
await wait(1500);
}
而";等待";功能:
function wait(milleseconds) {
return new Promise(resolve => setTimeout(resolve, milleseconds))
}
(来源(
这是有效的,但可能还有一段时间(<1500毫秒(存在缓存并且线程不知道。
我很乐意提供面糊溶液。