0

This bug has been killing me a week but I think I have narrowed it down to a strange behavior that I cannot explain. I'm sorry in advance for the long question but I'll try to be as clear as possible.

I'm using fast API and I had a endpoint such as this:

@app.get("/company/{tickers}/dosomething")
async def dosomething(tickers):
  query_statement = f""" 
  select *
  from mytable
  where ticker in { *tickers* }
  """

  #main_db_instance is a module I wrote to wrap my db connect via asyncpg.
  result_data = await main_db_instance.fetch_rows(query_statement)
  return jsonable_encoder(result_data)

This above works perfect! If you call it directly it works.

I then went step further and created a simple library to make data access easier for users

def requestCompanyReturning(ticker, endpoint):
  r = requests.get(f'myurl.com/company/{*ticker*}/{*endpoint*}', *headers*={'Authorization': f'{config.api_key}'})
  df = pd.read_json(r.content)
  return df



def dosomething(ticker):
  df = requestCompanyReturning(*ticker*, "dosomething") #calls above function to get data
  return df

 
dosomething(‘ibm’)

This works when called directly and when I give the library for users to access. Everything work fine so far.

My users started to use the library to build some cool things and it works perfectly on their machine and on a notebook.

I took their code and added a new fastapi endpoint:

@app.get("/company/{tickers}/dosomethingEvenCooler")
async def dosomethingcooler(tickers):
  var = dosomething(‘ibm’)
  var = #something even cooler than above happens here! Hold on to your hats!
  …

  return jsonable_encoder(var)

For some reason, not always but at this point, the var is empty. It’s driving me crazy but it’s not all the time. If I add a print statement under it, or sleep, it isn’t as often.

It feels totally random so I cannot figure out the cause but if I run a loop for 500 data points, many will fail but then I run it again and a totally different set will fail.

When I reviewed, it seems like when I call within my fast API app the requests for my requestCompanyReturning library call is empty. It works without any issues on our machines, colab notebooks and everywhere else but randomly on when called within a app it is empty.

Does anyone have any idea?

I checked the logs and do not see any errors related to a failure with the call. In fact I do see the calls from requests being made even when it fails/is empty after.

Lostsoul
  • 25,013
  • 48
  • 144
  • 239
  • 1
    It's a bad idea to have your web application call itself over HTTP. You should instead refactor your users' "cool thing" to get the JSON data from the database directly instead of using requests.get. – Mathias Rav Sep 11 '21 at 14:56
  • @MathiasRav I agree. The challenge here is there is 1 part time dev on this and many researchers putting together many models that we adjust fairly often. If this can work consistently then it would save me hours a week. We do not need the best performance so I'd like to see if this could work before recreating the queries. – Lostsoul Sep 11 '21 at 15:01
  • @MathiasRav also I was thinking, I'm not sure of why it's not a good idea? I can change the URL to localhost so it's not travelling over the internet. What makes it not good? wouldn't it be similar to calling another library but in this case the library is itself? – Lostsoul Sep 11 '21 at 15:27
  • I agree with the first comment and I think the point in that you use synchronous `requests` library. When request in progress event loop is waiting its finishing(hanging). If you need to make requests It is better to use asyncio based library. https://stackoverflow.com/questions/63872924/how-can-i-send-an-http-request-from-my-fastapi-app-to-another-site-api/63881674#63881674 – alex_noname Sep 11 '21 at 16:02
  • @alex_noname Thank you so much! I didn't even realize this option existed. Would I just replace my requests call with httpx? I'm not fully clear on the underlying issue. – Lostsoul Sep 11 '21 at 16:24
  • Yes, you can try just replace `requests` with `httpx` – alex_noname Sep 11 '21 at 16:27
  • @alex_noname thank you, changing it seems to been easy but oddly I'm getting timeouts that I didn't get before but If I resend the request it works. it's strange. – Lostsoul Sep 11 '21 at 17:58
  • @Lostsoul But why does it have to through the internet? You can even use the internal `Depends` mechanism in FastAPI to abstract away what needs to be re-computed for each of the views; in the first view you can just return it, in the second you can then do further processing with the same result. Or if you want to call it multiple times, inject a function that can be called to do the computation as necessary (or call an internal API instead). – MatsLindh Sep 11 '21 at 17:59
  • @MatsLindh I'm not familiar with this. I don't want to bother you to explain it, do you know what part of the documentation I read to understand what you are describing? I've never created or heard of this before so I'm not sure where to find it. – Lostsoul Sep 11 '21 at 18:17
  • https://fastapi.tiangolo.com/tutorial/dependencies/ - this works with any resource (you give it a function that is the dependency itself), and FastAPI will be smart and not reevaluate anything you've already evaluated for the current request, even if used in multiple dependencies. – MatsLindh Sep 11 '21 at 19:07
  • @MatsLindh I tried to go through it, am I understanding this correctly? The user builds the model using our library in a notebook(what they know best), then I take their code and all their library calls I turn into depends statement in the new endpoint? This way all the data is avail to the function just like it would be in their notebook? – Lostsoul Sep 11 '21 at 19:52

0 Answers0