簡體   English   中英

使用 Sanic 和 Redis 出現問題

[英]Trouble using Sanic and Redis

我正在與 2 名工人一起使用 Sanic。 我正在嘗試使計費系統正常工作,即計算用戶點擊 API 端點的次數。 以下是我的代碼:

class User(object):
    def __init__(self, id, name, age, address, mobile, credits=0):
        self.id = id
        self.name = name
        self.credits = count
        self.details = {"age": age, "address": address, "mobile_number": mobile}

上面的用戶 Class 用於制作我使用另一個 python 腳本上傳到 Redis 的對象,如下所示:

user = User(..., credits = 10)
string_obj = json.dumps(user)
root.set(f"{user.user_id}", string_obj)

當我想維護端點接收的命中數並使用用戶 object 跟蹤它並將其上傳回 Redis 時,就會出現主要問題。 我的代碼如下:

from sanic_redis_ext import RedisExtension

app = Sanic("Testing")
app.config.update(
{
    "REDIS_HOST": "127.0.0.1",
    "REDIS_PORT": 6379,
    "REDIS_DATABASE": 0,
    "REDIS_SSL": None,
    "REDIS_ENCODING": "utf-8",
    "REDIS_MIN_SIZE_POOL": 1,
    "REDIS_MAX_SIZE_POOL": 10,
})

@app.route("/test", methods=["POST"])
@inject_user()
@protected()
async def foo(request, user):
    user.credits -= 1
    if user.credits < 0:
        user.credits = 0
        return sanic.response.text("Credits Exhausted")

    result = process(request)

    if not result:
        user.credits += 1

    await app.redis.set(f"{user.user_id}", json.dumps(user))
    return sanic.response.text(result)

這就是我檢索用戶的方式:

async def retrieve_user(request, *args, **kwargs):
    if "user_id" in kwargs:
        user_id = kwargs.get("user_id")
    else:
        if "payload" in kwargs:
            payload = kwargs.get("payload")
        else:
            payload = await request.app.auth.extract_payload(request)
        if not payload:
            raise exceptions.MissingAuthorizationHeader()
        user_id = payload.get("user_id")

    user = json.loads(await app.redis.get(user_id))
    return user

當我使用 JMeter 以 10 個線程作為同一用戶測試 API 端點時,信用系統似乎不起作用。 在這種情況下,當用戶從 10 個積分開始時,他們最終可能會剩下 7 或 8 個(不可預測)積分,而他們應該還剩下 0 個積分。 據我說,這是由於工作人員沒有共享用戶 object 並且沒有變量的更新副本,這導致他們覆蓋彼此的更新。 誰能幫我找到解決方法,這樣即使同一個用戶同時點擊端點,他/她也應該被完美計費,用戶 object 應該被保存回 Redis。

問題是您從 Redis 中讀取了 credits 信息,將其扣除,然后將其保存回 Redis,這不是原子過程。 這是一個並發問題。

我不知道 Python,所以我將使用偽代碼。

首先為用戶 {user_id} 設置 10 個積分。

app.redis.set("{user_id}:credits", 10)

然后這個用戶進來了

# deduct 1 from the user credits and get the result
int remaining_credits=app.redis.incryBy ("{user_id}:credits",-1) 
if(remaining_credits<=0){
   return sanic.response.text("Credits Exhausted")} else{
   return "sucess" # or some other result}

將您的用戶信息與有效負載一起保存在其他地方並檢索“{user_id}:credits”並在您檢索用戶時將它們組合起來。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM