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

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

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

问题

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

# run.py
from functools import cache

import uvicorn
from fastapi import FastAPI, Depends

app = FastAPI()

class Dep:

    def __init__(self, inp):
        self.inp = inp

    @cache
    def __call__(self):
        print(self.inp * 100)
        return self.inp

@app.get("/a")
def a(v: str = Depends(Dep("a"))):
    return v

@app.get("/a/a")
def aa(v: str = Depends(Dep("a"))):
    return v

@app.get("/b")
def b(v: str = Depends(Dep("b"))):
    return v

@app.get("/b/b")
def bb(v: str = Depends(Dep("b"))):
    return v

def main():
    uvicorn.run(
        "run:app",
        host="0.0.0.0",
        reload=True,
        port=8000,
        workers=1
    )

if __name__ == "__main__":
    main()

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

英文:

I have a small fastapi example here

# run.py
from functools import cache

import uvicorn
from fastapi import FastAPI, Depends

app = FastAPI()


class Dep:

    def __init__(self, inp):
        self.inp = inp

    @cache
    def __call__(self):
        print(self.inp * 100)
        return self.inp


@app.get("/a")
def a(v: str = Depends(Dep("a"))):
    return v


@app.get("/a/a")
def aa(v: str = Depends(Dep("a"))):
    return v


@app.get("/b")
def b(v: str = Depends(Dep("b"))):
    return v


@app.get("/b/b")
def bb(v: str = Depends(Dep("b"))):
    return v


def main():
    uvicorn.run(
        "run:app",
        host="0.0.0.0",
        reload=True,
        port=8000,
        workers=1
    )


if __name__ == "__main__":
    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:

# run.py
from functools import cache

import uvicorn
from fastapi import FastAPI, Depends, Request

app = FastAPI()


@cache
def dep(inp):
    @cache
    def sub_dep():
        print(inp*100)
        return inp

    return sub_dep



@app.get("/a")
def a(v: str = Depends(dep("a"))):
    return v


@app.get("/a/a")
def aa(v: str = Depends(dep("a"))):
    return v


@app.get("/b")
def b(v: str = Depends(dep("b"))):
    return v


@app.get("/b/b")
def bb(v: str = Depends(dep("b"))):
    return v


def main():
    uvicorn.run(
        "run:app",
        host="0.0.0.0",
        reload=True,
        port=8000,
        workers=1
    )


if __name__ == "__main__":
    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:

确定