[英]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.