fastapi-cache icon indicating copy to clipboard operation
fastapi-cache copied to clipboard

Can't use separate cache configurations in an application

Open mjpieters opened this issue 2 years ago • 7 comments

While the FastAPICache object is implemented as a class, it is really just a singleton namespace; all attributes are class variables and all methods are class methods. All state it holds is global.

This means you can't define multiple cache configurations, hindering component-wise application construction.

E.g. if you wanted to store your RESTful API route cache in Redis, but use an in-memory cache for the HTML-heavy frontend portion of your application, you can't right now because there is just one global backend option. Nor can you set separate prefixes, unless you set a custom namespace for each route in a group of routes, something that's easy to get wrong.

The FastAPICache object should really be a real class. Instances could be used as the cache decorator, as well as let you adjust configuration with lifespan events:

cache = FastAPICache(prefix="fastapi-cache")


@asynccontextmanager
async def lifespan(app: FastAPI):
    redis = aioredis.from_url("redis://localhost")
    cache.backend = RedisBackend(redis)
    yield


app = FastAPI(lifespan=lifespan)

@app.get("/")
@cache(expire=60)
async def index():
    return dict(hello="world")

The cache object then has all the context it needs to access the backend and shared configuration but additional cache FastAPICache instances can be created with different settings.

For backwards compatibility the current cache decorator could be using a global singleton instance of FastAPICache() but issue a deprecation warning.

mjpieters avatar May 14 '23 12:05 mjpieters

Regarding compatibility, I have a question about whether some class methods in FastAPICache, such as init and get_backend, need to be backward compatible.

mkdir700 avatar May 17 '23 02:05 mkdir700

Regarding compatibility, I have a question about whether some class methods in FastAPICache, such as init and get_backend, need to be backward compatible.

Yes, if we are making an attempt at backwards compatibility here then the classmethods need to be retained for now.

Note that some of my recent PRs have already broken BC in places; switching the backends and coder to using bytes will break any custom coders. There will have to be a 'porting to #nextversion' section in the documentation, I think.

mjpieters avatar May 17 '23 10:05 mjpieters

The @cache decorator will use a default global instance of FastAPICache, which is temporarily named as default_cacher. When calling class methods such as FastAPICache.get_backend, FastAPICache.get_coder, and FastAPICache.get_key_builder, it actually accesses the properties related to the default_cacher.

Is my understanding above correct?

mkdir700 avatar May 17 '23 11:05 mkdir700

Is my understanding above correct?

Exactly. And these would all emit a deprecation warning.

mjpieters avatar May 17 '23 11:05 mjpieters

I got it. Are you currently implementing this feature? I can try to submit a PR for it.

mkdir700 avatar May 17 '23 12:05 mkdir700

I got it. Are you currently implementing this feature? I can try to submit a PR for it.

I have it on my list to implement, right after these dev environment changes I've been applying.

mjpieters avatar May 17 '23 13:05 mjpieters