fastapi: 如何在基于类的 (callable) 依赖中缓存 fastapi 依赖的值?

huangapple go评论126阅读模式
英文:

fastapi: how to cache the value of fastapi dependency in a class-based (callable) dependency?

问题

这是您提供的代码的翻译部分:

  1. # run.py
  2. from functools import cache
  3. import uvicorn
  4. from fastapi import FastAPI, Depends
  5. app = FastAPI()
  6. class Dep:
  7. def __init__(self, inp):
  8. self.inp = inp
  9. @cache
  10. def __call__(self):
  11. print(self.inp * 100)
  12. return self.inp
  13. @app.get("/a")
  14. def a(v: str = Depends(Dep("a"))):
  15. return v
  16. @app.get("/a/a")
  17. def aa(v: str = Depends(Dep("a"))):
  18. return v
  19. @app.get("/b")
  20. def b(v: str = Depends(Dep("b"))):
  21. return v
  22. @app.get("/b/b")
  23. def bb(v: str = Depends(Dep("b"))):
  24. return v
  25. def main():
  26. uvicorn.run(
  27. "run:app",
  28. host="0.0.0.0",
  29. reload=True,
  30. port=8000,
  31. workers=1
  32. )
  33. if __name__ == "__main__":
  34. main()

此外,您提供了额外的信息和第二种方法的代码,但您没有明确提出问题,所以我只提供了主要代码的翻译。如果您有任何进一步的问题或需要其他翻译,请告诉我。

英文:

I have a small fastapi example here

  1. # run.py
  2. from functools import cache
  3. import uvicorn
  4. from fastapi import FastAPI, Depends
  5. app = FastAPI()
  6. class Dep:
  7. def __init__(self, inp):
  8. self.inp = inp
  9. @cache
  10. def __call__(self):
  11. print(self.inp * 100)
  12. return self.inp
  13. @app.get("/a")
  14. def a(v: str = Depends(Dep("a"))):
  15. return v
  16. @app.get("/a/a")
  17. def aa(v: str = Depends(Dep("a"))):
  18. return v
  19. @app.get("/b")
  20. def b(v: str = Depends(Dep("b"))):
  21. return v
  22. @app.get("/b/b")
  23. def bb(v: str = Depends(Dep("b"))):
  24. return v
  25. def main():
  26. uvicorn.run(
  27. "run:app",
  28. host="0.0.0.0",
  29. reload=True,
  30. port=8000,
  31. workers=1
  32. )
  33. if __name__ == "__main__":
  34. main()

I run python run.py and the application spins up.

What I expect is that:

the first time I hit /a or /a/a endpoints it shows logs to me and print 100 "a" for me. the next times no logging happens because of the @cache decorator

and

the first time I hit /b or /b/b endpoints it shows logs to me and print 100 "b"s for me. the next times no logging happens because of the @cache decorator

What happens

The first time I hit /b, it shows logs. the next times no log
The first time I hit /b/b, it shows logs. the next times no log
The first time I hit /a, it shows logs. the next times no log
The first time I hit /a/a, it shows logs. the next times no log


the reason is that each time I am passing a value to the Dep class it is creating a new object and the call method is that of a new object each time. that is why the caching is not working properly.

and the caching is being done by fastapi dependency . That is why when I call an endpoint for the next times, I do not see new logs

But the question is how do I

  • pass arguments to the callable dependency (a class)
  • and also cache the value the function returns

Extra information

I tried to achieve the same using the approach below:

  1. # run.py
  2. from functools import cache
  3. import uvicorn
  4. from fastapi import FastAPI, Depends, Request
  5. app = FastAPI()
  6. @cache
  7. def dep(inp):
  8. @cache
  9. def sub_dep():
  10. print(inp*100)
  11. return inp
  12. return sub_dep
  13. @app.get("/a")
  14. def a(v: str = Depends(dep("a"))):
  15. return v
  16. @app.get("/a/a")
  17. def aa(v: str = Depends(dep("a"))):
  18. return v
  19. @app.get("/b")
  20. def b(v: str = Depends(dep("b"))):
  21. return v
  22. @app.get("/b/b")
  23. def bb(v: str = Depends(dep("b"))):
  24. return v
  25. def main():
  26. uvicorn.run(
  27. "run:app",
  28. host="0.0.0.0",
  29. reload=True,
  30. port=8000,
  31. workers=1
  32. )
  33. if __name__ == "__main__":
  34. main()

and it working as expected above

答案1

得分: 1

"The first time I hit /a, it shows logs. The next times, no log. The first time I hit /a/a, it shows logs. The next times, no log."

你第一次访问 /a 时,它会显示日志。接下来的访问,就不会有日志了。第一次我访问 /a/a 时,它也会显示日志。接下来的访问,仍然不会有日志。

You created four distinct objects at import time when you defined those functions, a pair of "a" functions and a pair of "b" functions. There's no relationship among those four objects, they are all separate from one another. So a GET that uses one has no effect on the other three.

import 时,您创建了四个不同的对象,分别是一对 "a" 函数和一对 "b" 函数。这四个对象之间没有关联,它们彼此独立。因此,对其中一个对象的 GET 请求不会影响其他三个对象。

Consider creating a cached a_result() helper function which both the /a and /a/a endpoints call. And similarly a b_result() helper shared by both /b and /b/b. Now there is a linkage across endpoints.

考虑创建一个 cacheda_result() 辅助函数,同时被 /a 和 /a/a 端点调用。同样,也创建一个被 /b 和 /b/b 共享的 b_result() 辅助函数。现在,端点之间确实存在链接。

(If web clients can send an arbitrary arg to such a helper, then prefer lru_cache instead, so there's no memory leak.)

(如果 Web 客户端可以向这样的辅助函数发送任意参数,请使用 lru_cache ,以避免内存泄漏。)

英文:

> The first time I hit /a, it shows logs. The next times, no log. The first time I hit /a/a, it shows logs. The next times, no log.

You created four distinct objects at import time
when you defined those functions, a pair of "a" functions and
a pair of "b" functions.
There's no relationship among those four objects,
they are all separate from one another.
So a GET that uses one has no effect on the other three.


Consider creating a
cached
a_result() helper function which both the /a and /a/a endpoints call.
And similarly a b_result() helper shared by both /b and /b/b.
Now there is a linkage across endpoints.

(If web clients can send an arbitrary arg to such a helper, then prefer
lru_cache
instead, so there's no memory leak.)

huangapple
  • 本文由 发表于 2023年7月27日 23:51:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76781485.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定