I'm working on a Python Web API using FastAPI
.
Currently it's a very tiny app but in the next few months I'm expecting it to have a few hundred routes
and services
.
This is an example of a route
I have:
my_service_1 = MyService1()
my_service_2 = MyService2()
@router.get("/route-1")
def route_1():
# Do something with the services
@router.get("/route-2")
def route_2():
# Do something with the services
@router.get("/route-3")
def route_3():
# Do something with the services
I left the services declaration at the top of the file for convenience, so all routes in the file can easily use them.
My question is, with hundreds of files like this, as soon as the application starts up, all routes will be registered, therefore all services will be instantiated. Is it a bad idea to do so? Would it cause too much memory usage given all services are now loaded into memory?
Would something like this be better in terms of performance/memory usage?
@router.get("/route-1")
def route_1():
my_service_1 = MyService1()
my_service_2 = MyService2()
# Do something with the services
@router.get("/route-2")
def route_2():
my_service_1 = MyService1()
my_service_2 = MyService2()
# Do something with the services
@router.get("/route-3")
def route_3():
my_service_1 = MyService1()
my_service_2 = MyService2()
# Do something with the services
Please forgive me if this is not a pythonic way of doing things, I came from a C# background.
TL;DR
Instantiating a new service at every request may be costly and I advice, if you can, to instantiate them all at the beginning and keep them ready for upcoming requests. You will reply faster (it depends on the service) and know before the resources that are needed by the app.
The answer is simple: there is no answer.
Jokes apart, it all depends on the use case. If you have an entire server dedicated to your app and no other app running, then you can use all of the resources available (not that you have to) and thus you are not bound by tight constraints. On the other hand, you may be running on limited resources, such as a shared server (like a cloud server), where other services may be running and switching from one server to another may mean a loss of information.
I'm not sure what you mean with "service", but if it's just a class that can be shared across multiple requests, then my advice is to instantiate them in a module (or package) and reuse them across requests.
Of course, if they require a lot of resources, say 0.5 GB of RAM, while your server only has 1 GB of RAM and users are requesting different services, as soon as you spawn a second service the system will crash.
In my experience, python (and especially the latest versions) are efficient enough for almost all use cases. The beauty is that you can scale it out, but again, it all depends on the expected usage, the context (what services are) and the constraints.
Example
Recently, I've been using the httpx library for communicating with another service in my web app. I was instantiating a client (or session for those coming from requests
) for every request. At a certain point I started getting some errors, due to a traffic increase.
The problem was the instantiation at every single request and having thousands of them, meant to perform a connection with the service continuously. So, I instantiated a client that connected once on server startup and was shared between the different functions/routes. It was even faster because I did not have to connect at every request, instead only once.