0

I've implemented a web app script that performs various actions, including making changes to a Google Sheet, which typically takes slightly more than 60 seconds.

However, despite setting timeout=360 or timeout=None, I sometimes encounter a TimeoutError in less than 30 seconds:

webAppsUrl = "https://script.google.com/macros/s/xxxxxxx/exec"
web_app_response = requests.get(webAppsUrl, headers=headers, timeout=360)
if web_app_response.text == 'Done':
    ...
else:
    print('Try Again!')

My WebApp script in Google Apps Script:

function doGet(e) {
  const lock = LockService.getDocumentLock();
  if (lock.tryLock(360000)) {
    try {
      All_Leagues_Funct();
      lock.releaseLock();
      return ContentService.createTextOutput('Done');
    } catch (error) {
      lock.releaseLock();

      const errorObj = {
        message: error.message,
        stack: error.stack
      };
      const folder = DriveApp.getFoldersByName("Error GAS").next();
      const file = folder.createFile(
        new Date().toString() + '.txt',
        JSON.stringify(errorObj, null, 2)
      );

      return ContentService.createTextOutput(error);
    }
  } else {
    return ContentService.createTextOutput('LockService Limit!');
  }
}

The issue is that even though I receive a TimeoutError, the web app script continues to run and makes changes to the spreadsheet. However, since the request has already timed out, I am unable to determine whether the web app completed its actions successfully and returned "Done", or if an error occurred.

To compound the problem, I am no longer aware of the remaining time for the web app to finish since I have already received a TimeoutError. This uncertainty makes it difficult to determine whether to make another call to prevent overlapping executions.

What would be the best solution or workaround to address this situation?

Traceback (most recent call last):
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connection.py", line 174, in _new_conn
    conn = connection.create_connection(
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\util\connection.py", line 95, in create_connection
    raise err
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\util\connection.py", line 85, in create_connection
    sock.connect(sa)
TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

During handling of the above exception, another exception occurred:     

Traceback (most recent call last):
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 703, in urlopen
    httplib_response = self._make_request(
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 386, in _make_request    
    self._validate_conn(conn)
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 1040, in _validate_conn  
    conn.connect()
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connection.py", line 358, in connect
    self.sock = conn = self._new_conn()
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connection.py", line 179, in _new_conn
    raise ConnectTimeoutError(
urllib3.exceptions.ConnectTimeoutError: (<urllib3.connection.HTTPSConnection object at 0x000001484196FCD0>, 'Connection to script.googleusercontent.com timed out. (connect timeout=360)')

During handling of the above exception, another exception occurred:     

Traceback (most recent call last):
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\adapters.py", line 440, in send
    resp = conn.urlopen(
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\connectionpool.py", line 785, in urlopen
    retries = retries.increment(
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\urllib3\util\retry.py", line 592, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))      
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='script.googleusercontent.com', port=443): Max retries exceeded with url: /macros/echo?user_content_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x000001484196FCD0>, 'Connection to script.googleusercontent.com timed out. (connect timeout=360)'))

During handling of the above exception, another exception occurred:     

Traceback (most recent call last):
  File "c:\Users\Computador\Desktop\Squads Python\squads_sw.py", line 539, in matches_infos
    web_app_response = requests.get(url, headers=headers, timeout=360)  
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\api.py", line 75, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\api.py", line 61, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py", line 529, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py", line 667, in send
    history = [resp for resp in gen]
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py", line 667, in <listcomp>
    history = [resp for resp in gen]
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py", line 237, in resolve_redirects     
    resp = self.send(
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\sessions.py", line 645, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\Computador\AppData\Local\Programs\Python\Python310\lib\site-packages\requests\adapters.py", line 507, in send
    raise ConnectTimeout(e, request=request)
requests.exceptions.ConnectTimeout: HTTPSConnectionPool(host='script.googleusercontent.com', port=443): Max retries exceeded with url: /macros/echo?user_content_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (Caused by ConnectTimeoutError(<urllib3.connection.HTTPSConnection object at 0x000001484196FCD0>, 'Connection to script.googleusercontent.com timed out. (connect timeout=360)'))
Digital Farmer
  • 1,705
  • 5
  • 17
  • 67
  • Although, unfortunately, I cannot know your actual script, in your situation, when LockService is used to Google Apps Script of Web Apps, what result will you obtain? And, when the timeout error occurs, was the error message returned from Web Apps? From your showing error message, I'm worried that the error might occur before a value is returned from Web Apps. How about this? I would like to confirm where your error occurs. First, I would like to correctly understand your current issue. – Tanaike Mar 27 '23 at 01:16
  • Hi @Tanaike ! I use ```LockService```, that in fact would not let an execution be done on top of the other. But anyway, as the error occurs in the ```request``` when I make the call, the Google script continues to run (it even finishes performing the actions perfectly), but since I use the ```request``` return to make sure everything was ok, I I can't define if I need to repeat it or not, because the error doesn't happen in the script specifically, but in the request. I added ```My WebApp script in Google Apps Script``` in the question. – Digital Farmer Mar 27 '23 at 01:33
  • And @Tanaike Additional information: the error does not occur every time, but sometimes randomly when it seems to me that the Google API is unstable, because I notice that when it occurs, sometimes I try to open Google Drive and the thumbnails of the files do not load, so it seems to be linked to a instability. – Digital Farmer Mar 27 '23 at 01:34
  • Thank you for replying. From your reply, I confirmed that in your actual script of Web Apps, LockService is used. And also, I confirmed that your error occurs before the script of Web Apps is finished. In your added script, what is `All_Leagues_Funct()`? Your current issue might be related to `All_Leagues_Funct()`? – Tanaike Mar 27 '23 at 01:47
  • @Tanaike ```All_Leagues_Funct()``` It is a function that encompasses all the activities that will be done, in the spreadsheet, in a Google drive document and sending a PDF created from the spreadsheet to my website. – Digital Farmer Mar 27 '23 at 02:02
  • @Tanaike The problem really happens when the ```request``` is not maintained until the end of the script execution, waiting for the final response. – Digital Farmer Mar 27 '23 at 02:02
  • @Tanaike I'm sure that during the execution of ```All_Leagues_Funct()``` no errors occur, because the last line of it, it defines the value "ALL DONE" in cell A1 of my worksheet, so if there were errors, this value would not appear and it always appears correctly and a text file with the error would be created in Google Drive. – Digital Farmer Mar 27 '23 at 02:04
  • Thank you for replying. I apologize for my poor English skill. Unfortunately, I cannot understand the relationship between `Additional information: the error does not occur every time, but sometimes randomly when it seems to me that the Google API is unstable, because I notice that when it occurs, sometimes I try to open Google Drive and the thumbnails of the files do not load, so it seems to be linked to a instability.` – Tanaike Mar 27 '23 at 02:16
  • and `I'm sure that during the execution of All_Leagues_Funct() no errors occur, because the last line of it, it defines the value "ALL DONE" in cell A1 of my worksheet, so if there were errors, this value would not appear and it always appears correctly and a text file with the error would be created in Google Drive.`. Can I ask you about the detail of your current situation? – Tanaike Mar 27 '23 at 02:16
  • Sure @Tanaike , I can definitely explain! Normally, there aren't any errors that occur, but on some random days when I make the request in Python, the Google script is triggered perfectly fine. However, seconds later, I receive the error that I mentioned in the question. Despite this, the Google script continues to execute and everything in the ```All_Leagues_Funct()``` function is carried out perfectly without any errors. – Digital Farmer Mar 27 '23 at 02:25
  • Thank you for replying. From your reply, the issue of `when it occurs, sometimes I try to open Google Drive and the thumbnails of the files do not load, so it seems to be linked to a instability.` in your comment is not related to Google Apps Script. Is my understanding correct? – Tanaike Mar 27 '23 at 02:28
  • @Tanaike Yes, that's correct. I just wanted to mention that I believe the issue occurs when there is some general instability with Google, because when the error happens, I open Google Drive to find my spreadsheet and check if the script is still running and making modifications. When I do this, I notice that the thumbnails of Google Drive files are not loading, indicating that something is not working perfectly on the platform. – Digital Farmer Mar 27 '23 at 02:31
  • 1
    Thank you for replying. From your provided information, when I could correctly replicate your situation, I would like to think of a solution. I deeply apologize that I cannot resolve your issue soon. I think that this is due to my poor skill. I apologize for my poor skill. – Tanaike Mar 27 '23 at 04:36

1 Answers1

0

Given that this doesn't happen often it may be reasonable to think that this could be a connectivity issue on your side, or even Google's. Either way, it may not be possible to expect 100% reliability from a server, so my suggestion is to take a different approach.

Instead of setting a timeout and waiting for a response you could just send a signal to the server to do its operations, and then check back after n seconds to see if the action was completed. To persist data you could use the Properties Service, where you can store variables indefinitely and you can define a status key to known whether or not the action was completed, and other keys to store timestamps, error messages, etc.

So for example, you can set a doPost() function that your Python script calls when you need to change the data, then Apps Script sets a status property in_progress, which changes to Done if it completes or Error GAS if it doesn't, then after a few seconds you can call a doGet() from Python that just returns the Properties, which you can analyze to determine whether or not the script did what it had to. The general convention is to use POST when you need to change data, and use GET when you only need to read it. Right now your script can be run by just opening the script URL in a browser, so it may be better in the long run to apply this change.

If your Python script is visible from the web you could also consider sending a POST request back to your Python script using UrlFetchApp() from Apps Script when it's done so it notifies you.

As an alternative, instead of using requests.get(), you could use requests.Session().get(), which I understand tries to create a persistent connection. I'm not too knowledgeable about this so I don't really know if it would make a difference but it may work for you. Either way I recommend the other methods instead.

Daniel
  • 3,157
  • 2
  • 7
  • 15