如何防止node.js中的竞争状况?

时间:2018-09-19 14:52:22

标签: javascript node.js synchronization

有人可以解释一下如何使用Express防止node.js中的竞争情况吗?

例如,有以下两种方法:

router.get('/addUser/:department', function(req, res) { ...})

router.get('/deleteUser/:department', function(req, res) { ...})

这两个函数都使用非阻塞I / O操作(例如写入文件或数据库)。

现在有人用部门“ A”呼叫“ addUser”,而某人试图删除部门“ A”的所有用户。如何解决此(或其他类似)比赛条件?

  1. 如果每个用户都有自己的文件/数据库记录,该如何解决该问题?

  2. 如果我有一个必须读取alter并再次写入的单个用户(文件系统)文件,该如何解决该问题?

注意:这只是一个理解的例子。这里不需要优化技巧。

2 个答案:

答案 0 :(得分:0)

(这是一个非常广泛的问题。)

通常,人们将使用数据库(而不是常规文本文件)并利用其内置的锁定机制。

<?php /* * Plugin Name: MyPlugin * Version: 1.00.00 * Plugin URI: * Description: Some Description * Author: Me * Author URI: * License: Copyright (c) 2018 Me. All rights reserved. */ if(!function_exists('myshortcode')){ function myshortcode($atts, $contents=''){ $atts = shortcode_atts( [ 'post_id' => '', ]); ... } } add_shortcode( 'myshortcode', 'myshortcode'); 数据库管理系统中的锁定机制示例:https://www.postgresql.org/docs/10/static/explicit-locking.html

答案 1 :(得分:0)

要归档此目标,您需要在两个服务中实现通信。

这可以通过简单的操作队列来依次处理每个请求来完成。 反作用是等待队列的请求将有一个延迟的响应(并可能发生超时)。

一个简单的“元”实现是:

const operationQueue = new Map();

const eventEmitter = new events.EventEmitter();

router.get('/addUser/:department', function(req, res) {
    const customEvent = `addUser-${new Date().getTime()}`;
    const done = () => { 
        res.send('done'); 
        operationQueue.delete(customEvent);
    };
    eventEmitter.once(customEvent, done);
    operationQueue.set(customEvent, () => addUser(customEvent, req));
})

router.get('/deleteUser/:department', function(req, res) {
    const customEvent = `deleteUser-${new Date().getTime()}`;
    const done = () => { 
        res.send('done'); 
        operationQueue.delete(customEvent);
    };
    eventEmitter.once(customEvent, done);
    operationQueue.set(customEvent, () => deleteUser(customEvent, req));
})

function addUser(customEvent, req){
    // do the logic
    eventEmitter.emit(customEvent, {done: true});
}

function deleteUser(customEvent, req){
    // do the logic
    eventEmitter.emit(customEvent, {done: true});
}

// not the best performance
setInterval(()=>{
    const process = operationQueue.shift();
    if(process) {
        process();
    }
}, 1);

当然,如果您要使用数据库或Redis队列之类的工具,则在健壮性和故障转移方面可能比该解决方案更合适。