Below is simple server written with FastAPI and running with Uvicorn.
In order to send the value to the next hop, the '/destination' url, I need to pass the value to the forward_request method.
In this implementation, passing the value is easy, because the calls' depth is just 1 function more.
But if I have a function that calls a function that calls a function...., I need to pass the value again and again and...
Is there a simpler way to share the value downstream without passing it?
Is there a way, without using inspect or some dark magic, to understand what is the scope that the function forward_request lives in?
Why am I asking this question?
I am using Jaeger for tracing and I need to forward the header x-request-id that I receive in the 1st server (/source in this example) to the 2nd server (/destination in this example).
If FastAPI\Uvicorn processed just 1 request at a time, I could have shared the value as a singleton class and access it from anywhere, but since requests are handled in parallel, the function forward_request doesn't have the context of who called it.
Some black magic
Function forward_request can inspect the call stack and figure from it, what is the value that was received, but that is one ugly way to do things.
Server Code
import asyncio
import aiohttp as aiohttp
from fastapi import FastAPI, Request
import uvicorn
from datetime import datetime
app = FastAPI()
@app.get("/source")
async def route1(value: int, request: Request):
print(f'source {value}')
start = datetime.now().strftime("%H:%M:%S")
await asyncio.sleep(5)
resp: dict = await forward_request(value)
end = datetime.now().strftime("%H:%M:%S")
return {
"start": start,
"end": end,
"value": value,
"resp": resp
}
@app.get("/destination")
async def route2(value, request: Request):
print(f'destination {value}')
start = datetime.now().strftime("%H:%M:%S")
await asyncio.sleep(5)
end = datetime.now().strftime("%H:%M:%S")
return {
"start": start,
"end": end,
"value": value
}
async def forward_request(value: int) -> dict:
async with aiohttp.ClientSession() as session:
async with session.get('http://127.0.0.1:5000/destination', params={'value': value}) as resp:
resp = await resp.json()
return resp
if __name__ == "__main__":
uvicorn.run("main2:app", host="127.0.0.1", port=5000, log_level="info", workers=1)