Server Timeout using Background Task Full Python 3.0 anvil.http.HttpRequestFailed: idle timeout:

What I’m trying to do:
From client side button click I’m calling:

# 
@anvil.server.callable
def generate_s1(website,company_name,current_user_uuid,homepage_copy_paste):
  task_object = anvil.server.launch_background_task('generate_s1',website,company_name,homepage_copy_paste)
  task_id = task_object.get_id()
  user_row = app_tables.users.get(customer_uuid=current_user_uuid)
  user_row.update(last_task_id=task_id)
  return task_id
#  ``` 

The background task that is called sends off an HTTP requests to an external workflow and returns a result in 120 - 140 seconds:

#
@anvil.server.background_task
def generate_s1(website,company_name,homepage_copy_paste):

  resp = anvil.http.request(url="https://*******.app.n8n.cloud/webhook/***********",
              method="POST",
              timeout=None,
              headers = {
                "Content-Type" : "application/x-www-form-urlencoded"
              },
              data = {
                "website" : website,
                "company_name" : company_name,
                "homepage_copy_paste" : homepage_copy_paste  
                },
              json = True,
              )
  print("resp is: ",resp)
  results = resp
  return results
# ``` 

Here is the error I’m receiving:

What I’ve tried and what’s not working:
I’ve placed this task in a background task because they don’t have the same 30 second timeout (seems though I’m experiencing a 60 second timeout).

I am running Full Python 3.0:
Screen Shot 2023-03-29 at 4.31.30 PM

Let me know what you guys think or if I’m missing some needed information.

That timeout seems like it’s coming from the HTTP request. In the API docs for it there’s a timeout parameter that makes it seem like you can adjust the default timeout: Anvil Docs | anvil.http

I dove into the code, the anvil.http.request() function resolves to a clojure function that uses a library called http-kit, the default timeout for a request in http-kit looks to be 60000 ms
(60 seconds), so that is definitely the error you are running into.

The python code using anvil.http.request should be specified in seconds though, it converts it to ms before passing it to clojure/JVM.

2 Likes

@ianb is correct. The default timeout is 60 seconds (even when set to None), although this is not stated in the API reference! I’ll add it to our list to fix.

So if you want a timeout longer than 60 seconds, you’ll have to set it as such.

2 Likes

Thanks @ianb and @brooke! I’ll set the timeout to 180000 which should be ample time and report back.

180000 will set it to 180,000 seconds, which is 2 and 1/12 days. That’s what I was pointing out, that the anvil.http.request(timeout= ) keyword argument is in seconds, not milliseconds, despite the confusing error that is stated in ms. (Its the Java error from http-kit bubbling back up through python)

Just setting it to timeout=180 would get you 3 minutes instead of the default 60 seconds.

Edit: I forgot to add where I got this undocumented information from, it’s in http.py found in the open source server, this is what it looks like:
image

2 Likes

Copy that @ianb - I have been running it in the last hour with the timeout as 180,000 which I will adjust down to 180 now.

I’m starting to see a different error which is progress:

I ran this request through Postman and I’m getting a Gateway timeout error instead which comes back at HTML which might explain the “Invalid JSON” error in the photo above:

@ianb would this be due to the external workflow which is catching the POST request? Note, it’s an n8n.io workflow. The workflow completes, but it looks like the Gateway Times Out before then.

Thoughts on how to solve for that?

If you think you are getting an error response that isn’t json, setting json = False should probably let you at least see the content of the response instead of raising an HttpError error.

Again, I don’t have any special insights into the type of http request code you are writing, I just happened to have the open source anvil-runtime open in my VScode editor and did a search, and from reading it, any json decoding error seems to raise the error you are describing, not anything specific.

1 Like

For anyone else in the future, catch the error with:

try:
  #  Your request code here
except anvil.http.HttpErrorStatus as err:
  print(err.content)

And you can access the non-json content through err.content
This might work to access the non json content that is causing the error, ̶h̶o̶w̶e̶v̶e̶r̶ ̶I̶ ̶h̶a̶v̶e̶ ̶n̶o̶t̶ ̶t̶e̶s̶t̶e̶d̶ ̶i̶t̶.̶ I just tested it in IDLE and there is no reason it should not work.

The app still shows a timeout error even with a timeout set to None or with timeout set to 180 or longer. Any other insights for this issue?

@ianb - Do I need to declare the HttpErrorStatus above the exception line?

I’m seeing this issue:

@anvil.server.background_task
def answer_onboarding_questions(homepage,offer_page,company_name,freebie,niche,track_record):
  print("I am line 217 on ServerModule1")
  try:
    resp = anvil.http.request(url="https://***.app.n8n.cloud/webhook/***-5d5744efc9a0",
                  method="POST",
                  json = True,
                  timeout=None,
                  headers = {
                    "Content-Type" : "application/x-www-form-urlencoded"
                  },
                  data = {
                    "homepage" : homepage,
                    "offer_page" : offer_page,
                    "company_name" : company_name,
                    "freebie": freebie,
                    "niche": niche,
                    "track_record": track_record                    
                    },
                  )
  except HttpErrorStatus as err:    
    print(err.content)
    
  print("resp is: ",resp)

  results = resp['choices'][0]['message']["content"]
  print("results is: ",results)
  return results

untested, but you could try:

from anvil.http import HttpErrorStatus

at the top.

or

  except anvil.http.HttpErrorStatus as err:    
    print(err.content)