使用信号量修复并发问题 [英] Use a Semaphore to fix a Concurrency Issue

查看:102
本文介绍了使用信号量修复并发问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近问了一个问题:链接此处关于将刷新令牌存储在我的autodesk-forge Web应用程序中的最佳方法.我目前将刷新令牌存储在一个只有一行和一列的SQL数据库中,其中包含刷新令牌.有关令牌的步骤如下:

I recently asked a question: link here regarding the best way to store refresh tokens in my autodesk-forge web application. I am currently storing the refresh token in an SQL database with only one row and column, containing the refresh token. Steps regarding the token are as follows:

  1. 用户登录时,将调用GET方法以从数据库中检索最新令牌. Returndata.php只需连接到SQL DB并从表中检索行.获取方法代码:

function getRefreshToken() {
    $.get("returndata.php",
        function(response) {
            var res = JSON.parse(response);
           console.log(response);
            console.log(res);
            refreshToken = res[0].Value;
           // console.log(refreshToken);
            useRefresh();
           // console.log(response.value);
            //var times = response.times;
        }, 
    );  
}

  1. 该令牌被返回并用于获取用户的访问令牌.
  2. 检索访问令牌时,它带有刷新令牌,该刷新令牌随后与上一个刷新令牌存储在SQL数据库的同一行中. Savesettings.php只需连接到数据库并使用新的刷新令牌更新单行.用于存储刷新令牌的POST方法的代码:

function saveRefreshToken() {
    
    $.post("savesettings.php",
    {
       Value: refreshToken,
    },
    function(data, status){
    console.log(data);
  });
    
}

在大多数情况下,此方法都可以正常工作,但是在某些情况下,该方法仍然存在问题.我相信这是由于并发问题引起的.如果两个用户在非常相似的时间访问数据库,则数据可能会损坏或给出错误的数据.要解决此问题,我知道我需要使用信号量,以便其他请求等到第一个请求完成后再执行.我如何使用信号量来实现这一目标?任何帮助将不胜感激,因为我对此问题非常执着.谢谢.干杯!

For the most part, this method works fine, however there have been a couple times where it has bugged out. I believe this is due to a concurrency issue. Where if two users are accessing the DB at very similar times, the data may become corrupted or the wrong data may be given. To fix this, I know I need to use a semaphore so that other requests wait until the first is done before executing. How can I use a semaphore to achieve this? Any help would be greatly appreciated as I am very stuck on this issue. Thanks. Cheers!!

编辑

function getToken(){
    $.ajax({
    method: 'POST',
    url: 'https://developer.api.autodesk.com/authentication/v1/gettoken',
    headers: {
        'Content-Type':'application/x-www-form-urlencoded'
    },
    data:'client_id=xxxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxx&grant_type=authorization_code&code=' + code + '&redirect_uri=xxxxxxxxxxxxxxxxxxxxxx',
    
    success:function(response){
       // console.log(response);
        access_token = response.access_token;
        console.log(access_token);
        console.log(response);
        refreshToken = response.refresh_token;
        saveRefreshToken()
        
    }
})
}

function useRefresh(){
$.ajax({
    method:'POST',
    url: 'https://developer.api.autodesk.com/authentication/v1/refreshtoken',
    headers: {
        'Content-Type':'application/x-www-form-urlencoded'
    },
    data:'client_id=xxxxxxxxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxx&grant_type=refresh_token&refresh_token='+refreshToken+'&scope=data:read',
success:function(response){
    console.log(response);
    refreshToken = response.refresh_token;
    //console.log(refreshToken);
    access_token = response.access_token;
    saveRefreshToken();
}
})
}

推荐答案

仅与MySQL竞速问题有关时,Evert是正确的.在您的情况下,您还要调用另一台服务器来获取访问令牌.这意味着我们需要在刷新时锁定表以进行读/写.

Evert is correct when it is related to MySQL racing issue only. In your case, you are also calling another server to fetch an access token; meaning we need to lock the table for read/write while doing a refresh.

我已经在此处编写了一个小示例,它做了最少的工作解决问题.但是,正如Evert所说,如果您选择信号量方法,它将只能在单个服务器上处理HTTP请求.如果要进行负载平衡,则需要使用mysql/redis锁定方法.我说过Redis,因为在该主题上,它比mysql更好.

I have written a little example here, which does the minimum things to solve the issue. However, as Evert said, it would only work on a single server to handle HTTP requests if you choose the semaphore approach. If you are doing load balancing, we would need to use the mysql/redis lock approach. I said Redis, because it would be a better choice than mysql on that topic.

该示例还将向您展示在Forge应用程序中获取令牌的正确方法.在上面的代码中,我注意到您正在使用$ .ajax()代码,这意味着您正在从HTML页面(在客户端上)在OAuth服务器上进行HTTP调用-这样做会使您面临高安全性问题,您正在泄漏自己的代码访问令牌和clientID/秘密密钥.任何人都可以在不知情的情况下窃取您的clientID/秘密并开始使用您的帐户.

The sample will also show you the right way to fetch token(s) in a Forge application. In the code above I noticed you were using $.ajax() code, meaning you were doing HTTP calls on the OAuth server from the HTML page (on the client?) - doing this expose you to high security problem, you are leaking your access tokens, and clientID/secret keys. Anyone can steal your clientID/secret and start using your account without you knowing.

您应该发行2个访问令牌,一个具有最低特权的公共令牌(该令牌仅用于查看器).具有附加特权的第二个令牌将保留在服务器上,并且永远不会公开给任何客户端应用程序.

You should be issuing 2 access tokens, one public with minimum privileges (this one will be used for the Viewer only). The second token, with additional privileges, will remain on the server and will never be exposed to any client application.

该示例执行2个简单的操作:

The example does 2 simple operations:

  • 使用公共令牌在查看器中显示模型
  • 使用内部令牌列出存储桶或文件夹中的模型

该示例还显示了2条腿流和3条腿代码流.从理论上讲,两者应该以相同的方式工作,但是有一个重要的区别要知道.

The sample also show a 2 legged flow and a 3 legged code flow. While in theory both should be working the same way, there is an important difference to know.

  1. 您可以随时生成任意数量的2腿标记.这意味着您将始终获得有效的令牌,即使您同时多次令牌也是如此.实际上,您不刷新令牌,而是每次都创建一个新令牌,并且这样做不会使以前生成的令牌无效.该示例有点懒,只需在需要时立即获取令牌,而不会打扰服务器处理的HTTP请求.

  1. You can generate as many 2 legged token you want, any time. It means that you will always get a valid token, even if you your token multiple times at the same moment. You actually, do not refresh a token, you create a new one each time, and doing that does not invalidate previous generated tokens. The sample is a bit lazy, and just fetch now token whenever it needs without bothering of the HTTP requests handled by the server.

虽然您也可以生成任意数量的3个腿标记(代码流),但是由于每次创建新令牌时都需要登录这一事实,您会受到限制.但是,当您创建访问令牌时,将获得一个刷新令牌,该令牌将使您每次需要时都可以更新access_token.但是,刷新令牌有3个警告:

While you can generate as many 3 legged token (code flow) you want as well, you would be limited by the fact you need to login each time you create a new one. However, when you create an access token, you get a refresh token coming with it which will let you renew the access_token every-time you need. However, there is 3 caveats on refreshing tokens:

  • 刷新令牌仅在14天有效,因此您需要至少每14天刷新一次.
  • 首次创建令牌时,需要提供可能需要的所有范围.刷新令牌时,您可以降级作用域,但将永远无法添加新的作用域.
  • 无论何时使用刷新令牌,该令牌都会丢失,但您会得到一个新令牌.最后一个令牌是您接下来需要使用的令牌.

要使用2legged版本,只需进入服务器的根目录,例如http://localhost/

To use the 2legged version, just got to the root of your server, for example http://localhost/

要使用3legged版本,请访问http://localhost/login以创建一对新的令牌,否则请访问http://localhost/www/bim360.html

To use the 3legged version, go to http://localhost/login for creating a new pair of tokens, otherwise go to http://localhost/www/bim360.html

还有一个小的测试示例,它将在您的服务器上同时触发5个HTTP请求.我将我的Apache实例限制为一次只能处理2个请求,这是为了验证在更新令牌时,所有请求都不会互相竞争,这会使您的令牌/刷新令牌不同步.

There is also a little test example which will fires 5 HTTP request at the same time on your server. I limited my Apache instance to process 2 requests at a time, this is to verify that when renewing tokens, all request are not racing each others which will make your token/refresh token out of sync.

自述文件应该足够部署示例并浏览代码的详细信息.

The readme should have enough details to deploy the sample and navigate through the code.

这篇关于使用信号量修复并发问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆