在无状态操作上等待 Lock()
await for Lock() on stateless action
问题:
前端页面发出x个并行请求(姑且称之为第一组),
下一组(x 请求)将在 5 秒后,第一个请求(第一组)从数据库设置缓存。
其他 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 );
}
作为解决方法,我添加了“最终”范围以在第一次启动后从缓存中删除锁键,并且:
while(myCache.has( "lockFlag" )){
await wait(1500);
}
以及“等待”函数:
function wait(milleseconds) {
return new Promise(resolve => setTimeout(resolve, milleseconds))
}
(source)
这是有效的,但仍然可能有时间(<1500 毫秒)有缓存并且线程不知道。
我很乐意提供连击解决方案。
您可以尝试给出的方法 here,稍作修改以将其应用于您的案例。
- 为简洁起见,我删除了注释并缩短了变量名称。
代码,然后解释:
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"
),然后继续从 db 检索 table 数据。与此同时:
- 其他一些代码调用
getDataFromDB
。但是,该代码将第一个 if
块评估为真,因此它等待承诺,直到发出 unlocked
事件。
- 回到第一个调用代码:它完成它的逻辑,缓存 table 数据,将
lockFlag
设置回 false,发出一个 unlocked
事件,并且 returns.
- 其他代码现在可以继续执行:它将第二个
if
评估为真,因此它从缓存中获取 table,并且 returns.
问题:
前端页面发出x个并行请求(姑且称之为第一组), 下一组(x 请求)将在 5 秒后,第一个请求(第一组)从数据库设置缓存。 其他 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 );
}
作为解决方法,我添加了“最终”范围以在第一次启动后从缓存中删除锁键,并且:
while(myCache.has( "lockFlag" )){
await wait(1500);
}
以及“等待”函数:
function wait(milleseconds) {
return new Promise(resolve => setTimeout(resolve, milleseconds))
}
(source)
这是有效的,但仍然可能有时间(<1500 毫秒)有缓存并且线程不知道。
我很乐意提供连击解决方案。
您可以尝试给出的方法 here,稍作修改以将其应用于您的案例。
- 为简洁起见,我删除了注释并缩短了变量名称。
代码,然后解释:
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"
),然后继续从 db 检索 table 数据。与此同时: - 其他一些代码调用
getDataFromDB
。但是,该代码将第一个if
块评估为真,因此它等待承诺,直到发出unlocked
事件。 - 回到第一个调用代码:它完成它的逻辑,缓存 table 数据,将
lockFlag
设置回 false,发出一个unlocked
事件,并且 returns. - 其他代码现在可以继续执行:它将第二个
if
评估为真,因此它从缓存中获取 table,并且 returns.