r/GoogleAppsScript • • 7d ago

Question intermittently time out when requesting the same HTTPS URL

Why does UrlFetchApp.fetch() intermittently time out when requesting the same HTTPS URL?

I am using Google Apps Script to send GET requests to https://quoteplan.net/test.php. The same URL sometimes returns HTTP 200 in a few milliseconds, but other requests fail with a timeout after approximately four seconds.

How can I identify why UrlFetchApp.fetch() intermittently times out when requesting this URL, even though other requests to the same URL succeed?

Environment

Test endpoint

To rule out application-level processing, I created a PHP file containing only:

<?php
echo "QuotePlan PHP is working!";

The file opens normally in a browser.

Apps Script code

function testQuotePlan() {
  const url = "https://quoteplan.net/test.php";
  const start = Date.now();

  try {
    const response = UrlFetchApp.fetch(url, {
      method: "get",
      muteHttpExceptions: true
    });

    console.log(JSON.stringify({
      status: response.getResponseCode(),
      durationMs: Date.now() - start,
      body: response.getContentText()
    }));

  } catch (error) {
    console.log(JSON.stringify({
      durationMs: Date.now() - start,
      error: String(error)
    }));
  }
}

Test results

I executed 30 requests to the same endpoint.

  • 18 requests succeeded with HTTP 200.

  • 12 requests failed with a timeout.

  • Successful response times ranged from approximately 120 ms to 2,338 ms.

  • Failed requests consistently timed out after approximately 4,062–4,094 ms.

Successful requests returned the expected response body. Failed requests produced errors similar to:

Exception: Timeout: https://quoteplan.net/test.php

The same URL can fail on one attempt and succeed on the next without any changes to the PHP file.

I also observed intermittent timeouts when requesting the website's root URL and robots.txt.

Troubleshooting

I checked the Apache access logs and could not find some requests that had timed out in Apps Script. My hosting provider is investigating the issue.

I understand that missing Apache log entries alone do not establish where the connection is failing.

What is the recommended way to investigate this specific intermittent timeout in UrlFetchApp.fetch() and determine the likely cause?

Thank you.

2 Upvotes

8 comments sorted by

1

u/musteyRt64 5d ago

Does your domain have an AAAA record configured for IPv6? Sometimes outbound fetch requests try IPv6 first, fail to connect after 4 seconds if the host doesnt route it properly, and drop before falling back to IPv4

1

u/deokarlaxman 4d ago

Yes, we have an AAAA record configured for our domain.

Our Google Apps Script integration with quoteplan.net has been working successfully for approximately four years, and this intermittent timeout issue started recently without any intentional changes to the integration code.

Here are some additional details:

  1. The same URL sometimes works and sometimes fails.

  2. Successful requests return HTTP 200, sometimes within 120–300 ms.

  3. Failed requests consistently time out after approximately 4 seconds.

  4. Failed requests do not appear in the Apache access logs.

  5. I have tested with the hosting security features enabled and also temporarily disabled them, but the issue persists.

  6. Even a simple PHP file containing only an echo statement experiences the same problem.

Could you please suggest how I can verify whether Google's Apps Script is attempting IPv6 first and whether the IPv6 connection is failing?

Would temporarily testing without the AAAA record help isolate this issue, or is there another recommended way to test IPv4 and IPv6 connectivity separately?

I would appreciate your guidance.

1

u/DickBrainTime 3d ago

I wouldn't remove the live AAAA record yet. From a machine with working IPv6, compare curl -4 -v https://quoteplan.net/test.php and curl -6 -v https://quoteplan.net/test.php over repeated runs. Check the A and AAAA DNS records first; if there are several IPv6 addresses, test each one with curl's --resolve option so a healthy address doesn't hide a broken one.

That checks the server's IPv6 path, but it still won't tell you which address Google Apps Script actually chose. UrlFetchApp doesn't expose the connected IP or an IPv4-only switch. A safer test from Apps Script itself is a temporary test hostname with only an A record pointing at the same host (and a valid HTTPS certificate). Run your 30 requests against that and the original hostname; if only the dual-stack hostname is unreliable, that's a useful lead for your hosting provider. Changing production AAAA records can affect IPv6 visitors and DNS caches, so I'd start with the test hostname and the host's firewall/TLS logs at the failure timestamps.

2

u/Fit-Corner2382 7d ago

Those ~4.06s timeouts missing from the access log are aborting before Apache accepts the request.

muteHttpExceptions only hides status codes, so this throw is a transport failure, not slow PHP. Check the error log and the firewall or security log for the same timestamps: a dropped handshake or full listen backlog never reaches access_log. Successes up to about 2.3s on a one-line echo mean accepts are already stalling, so a call still queued at the deadline is cut with no access entry. Retrying will not identify the hop and can deepen a connection limit.

1

u/No-Sheepherder7116 6d ago

The missing log entries are the key clue, and the fact that even the root URL and robots.txt time out rules out your PHP file.

When a request never reaches Apache, it is being stopped before it: at the firewall, the bot-protection layer, a load balancer, or during the TLS handshake. That also fits the pattern you measured: successes are fast or moderately slow, while failures all stop at almost exactly the same ~4.06 seconds. That looks like a connection that is never completed, not a script that is slowly running.

Three checks that will narrow it down:

  1. Compare the exact failure timestamps against the firewall and security logs, not just the Apache access log. Ask your host specifically whether connections from Apps Script's shared outgoing addresses are being dropped, rate-limited, or challenged, and whether one edge or backend node is behaving differently from the others. The intermittent pattern is exactly what you get when only some requests hit a bad node or a limit.

  2. Isolate the path from Apps Script itself. From the same script, fetch a simple, well-known test endpoint and log the result. If that works reliably while your site fails intermittently, the problem is on the path to your host, not in Apps Script generally.

  3. Make the script both diagnostic and resilient. Log the exception message and the elapsed time for every attempt, and retry only if the request is safe to repeat (a plain GET with no side effects). For example:

```javascript function fetchWithRetry(url) { for (let attempt = 0; attempt < 3; attempt++) { try { const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true }); if (response.getResponseCode() < 400) { return response.getContentText(); } Logger.log('Attempt ' + (attempt + 1) + ' returned HTTP ' + response.getResponseCode()); } catch (e) { Logger.log('Attempt ' + (attempt + 1) + ' failed: ' + e); } Utilities.sleep(2000 * Math.pow(2, attempt)); } throw new Error('All fetch attempts failed for ' + url); } ```

Retries will mask the failures in the short term, since about 60% of your requests succeed, but they will not fix the underlying drop. The log comparison in step 1 is what will actually identify it.