PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, September 5, 2022

[FIXED] What is the recommended way to instantiate and pass around a redis client with FastAPI

 September 05, 2022     fastapi, python, redis     No comments   

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)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing