Issue
I'm using FastAPI with Redis. My app looks something like this
from fastapi import FastAPI
import redis
# Instantiate redis client
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
# Instantiate fastapi app
app = FastAPI()
@app.get("/foo/")
async def foo():
x = r.get("foo")
return {"message": x}
@app.get("/bar/")
async def bar():
x = r.get("bar")
return {"message": x}
Is it bad practice to create r
as a module-scoped variable like this? If so what are the drawbacks?
In Tiangolo's tutorial on setting up a SQL database connection he uses a dependency, which I guess in my case would look something like this
from fastapi import Depends, FastAPI
import redis
# Instantiate fastapi app
app = FastAPI()
# Dependency
def get_redis():
return redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
@app.get("/foo/")
async def foo(r = Depends(get_redis)):
x = r.get("foo")
return {"message": x}
@app.get("/bar/")
async def bar(r = Depends(get_redis)):
x = r.get("bar")
return {"message": x}
I'm a bit confused as to which of these methods (or something else) would be preferred and why.
Solution
Depends
will evaluate every time your function got a request, so your second example will create a new connection for each request. As @JarroVGIT said, we can use connection pooling to maintain the connection from FastAPI to Redis and reduce open-closing connection costs.
Usually, I create a different file to define the connection. Let's say we have config/db.py
:
import redis
def create_redis():
return redis.ConnectionPool(
host='localhost',
port=6379,
db=0,
decode_responses=True
)
pool = create_redis()
Then in the main.py
from fastapi import Depends, FastAPI
import redis
from config.db import pool
app = FastAPI()
def get_redis():
# Here, we re-use our connection pool
# not creating a new one
return redis.Redis(connection_pool=pool)
@app.get("/items/{item_id}")
def read_item(item_id: int, cache = Depends(get_redis)):
status = cache.get(item_id)
return {"item_name": status}
@app.put("/items/{item_id}")
def update_item(item_id: int, cache = Depends(get_redis)):
cache.set(item_id, "available")
return {"status": "available", "item_id": item_id}
Usually, I also split the dependencies file like the doc so we can call it from our routing module, but for simplicity, I will leave it like this.
You can check this repo to experiment by yourself. It has more comprehensive code and I have already created several scenarios that might help you understand the difference. And it will also cover how your first example may block other endpoints.
Answered By - Tegar Answer Checked By - Mary Flores (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.