2

Our Chrome extension has both content and background scripts communicating with each other. When the plugin is updated, the background script is stopped and the content scripts start getting Error: Extension context invalidated.. In V2, we used port.onDisconnect event as described here to clean things up. But in V3, this event is also sent after 5 minutes (when the background service worker is automatically terminated). So this event now means either extension unloading (and the cleanup should be done), or just SW lifecycle event (no need to cleanup, reconnecting is fine).

So the question is, how to unambiguously determine whether the cleanup is necessary.

I've tried:

  1. chrome.management. events: onDisabled etc. But unfortunately chrome.management is undefined in my content script.
  2. Checking for chrome.runtime.id inside port.onDisconnected callback to determine the plugin is unloaded. But the id is still present at that moment.
  3. Again inside port.onDisconnected, trying to do chrome.runtime.connect() again and catching the exception. But there's no exception! The port is created successfully, but it receives neither messages nor its own onDisconnected events.
  4. Trying point 3 inside setTimeout(..., 0) and setTimeout(..., 100). The former doesn't produce exceptions either. The latter does, but it introduces a delay of questionable duration (why 100? would it work the CPU is overloaded?) and potential race conditions when other plugin functionality could try to send messages with unpredictable results. So I'd appreciate a more bullet-proof solution.
Peter Gromov
  • 17,615
  • 7
  • 49
  • 35
  • You can [keep the service worker alive](https://stackoverflow.com/a/66618269). See also [How to remove orphaned script after update](https://stackoverflow.com/a/57471345) – wOxxOm May 13 '22 at 11:48
  • Thank you! But if to keep the SW alive I have to periodically reconnect all ports, how do I tell the port was disconnected by the unloading and not by SW itself? Unfortunately the second approach works only with extension update, not unloading :( – Peter Gromov May 13 '22 at 12:59
  • As long as you keep reconnecting the ports as shown in that answer the SW won't unload by itself. – wOxxOm May 13 '22 at 13:31

1 Answers1

3

Thanks to wOxxOm's suggestions, I've found a solution that seems to work for now: every once in a while (<5 seconds) to disconnect the port in the content script and then reconnect again. The code looks like this:

let portToBackground: chrome.runtime.Port | undefined = openPortToBackground();

function openPortToBackground(): chrome.runtime.Port {
    const port = chrome.runtime.connect();

    const timeout = setTimeout(() => {
        console.log('reconnecting');
        portToBackground = openPortToBackground();
        port.disconnect();
    }, 2 * 60 * 1000); // 2 minutes here, just to be sure

    port.onDisconnect.addListener(() => {
        clearTimeout(timeout);
        if (port !== portToBackground) return;

        // perform the cleanup
    });

    return port;
}

export function isExtensionContextInvalidated(): boolean {
    return !portToBackground;
}
Peter Gromov
  • 17,615
  • 7
  • 49
  • 35