WebWorker
WebWorker

Reputation: 9

POST Requests Fail with "Uncaught (in promise) TypeError: Failed to fetch" on Tab Switch

I am sending a great amount of events in batches of 20 events to an analytics tables in BigQuery. Initially, I used sendBeacon but switched to using regular POST requests. Below is the class I use to handle sending events:

import { createControllablePromise, delay } from '../utils/generalUtils';

class EventReporterWorker {
  #requestQueue = Promise.resolve();
  #activeRequest;
  #isPageVisible = true;

  #handleSendEvents = async eventsPayload => {
    if (this.#isPageVisible) {
      await this.#activeRequest;
    }

    const currentRequestPromise = createControllablePromise();
    const cancelTimeout = setTimeout(() => currentRequestPromise.resolve(), 30000);
    currentRequestPromise.finally(() => clearTimeout(cancelTimeout));

    this.#activeRequest = currentRequestPromise;

    const requestPromise = fetch('*MY_URL*, {
      method: 'POST',
      headers: {
        accept: '*/*',
        'cache-control': 'no-cache',
        'content-type': 'text/plain;charset=UTF-8',
      },
      body: eventsPayload,
      keepalive: true,
      mode: 'no-cors', // Matches sendBeacon's behavior
    });

    requestPromise.finally(() => {
      currentRequestPromise.resolve();
    });

    if (this.#isPageVisible) {
      try {
        await delay(300);
        await requestPromise;
      } catch (e) { }
    }
  };

  sendEvents = async eventsPayload => {
    const newRequestsQueue = this.#requestQueue.then(() => this.#handleSendEvents(eventsPayload));
    this.#requestQueue = newRequestsQueue;
    return newRequestsQueue;
  };

  setPageVisible = isPageVisible => {
    this.#isPageVisible = isPageVisible;
    if (!isPageVisible) {
      this.#activeRequest.resolve();
    }
  };
}

export const eventReporterWorker = new EventReporterWorker();

I am using promises because I receive events from multiple places and want them to be executed sequentially. The only time I want all the events to be sent immediately is when I switch tabs.

However, when switching tabs, some of the POST calls fail and stuck on Pending status.

The error message is:

Uncaught (in promise) TypeError: Failed to fetch

Events before and after this failure succeed, as shown in the image.

Has anyone encountered this issue or have any ideas on how to fix it?

I’ve tried sending events in batches, added delays, checked the server (the issue isn't on the server side), and confirmed that the internet connection is fine. The call seems to fail at the browser level.

reference image

Upvotes: 0

Views: 34

Answers (1)

jggp1094
jggp1094

Reputation: 180

Seems like you have a similar case here. The "TypeError: Failed to fetch" error usually occurs for multiple reasons:

  • An incorrect or incomplete URL has been passed to the fetch() method.

  • The server you are making a request to does not send back the correct CORS headers.

  • A wrong protocol is specified in the url.

  • A wrong method or headers have been passed to the fetch() method.

While keepalive is designed to help with this, it doesn’t guarantee the request will complete. Your mode: 'no-cors' exacerbates the issue because no-cors requests are limited in the information they can return, making it hard to detect actual failures versus browser-terminated requests.

Unless absolutely necessary, avoid no-cors. It severely limits error handling and can hide important information about request failures. Correctly configuring CORS on your server is the recommended approach.

Upvotes: 0

Related Questions