I have struggled with this issue recently and have seen this question posted a number of times with minimal answers or support. I wanted to provide some feedback on what I discovered in my investigation and maybe it could be helpful to you.
Background:
A few months back, we started receiving occasionally complaints from some of the users that the Chrome extension is no longer functioning. Essentially, buttons were not being inserted into their webpage as expected. Users had the ability to login to our system from the extension icon, but it did not trigger the scripts to run in the tab. The only way to resolve the issue was by restarting the browser or the computer.
The extension registers a number of alarms, an onTabUpdate listener, and an onMessage listener, none of which were responding. Even when opening the devtools, I could not do any actions, like sending a message, or even call chrome.runtime.reload(), and no logs appeared.
A couple of key notes:
- The issue would appear after a few days of use without issue
- Not all users experienced the issue
- It happened over multiple versions of the extension
Investigation:
Using chrome://serviceworker-internals, I was able to identify that during normal behavior, the extension would enter a RUNNING status when the alarms triggered or when the tab was changed/opened and after 30 seconds of inactivity, the extension would change to a STOPPED state, but would reenter the RUNNING state when there was an event or message.
Findings:
Since I cannot reproduce the issue on my own, I cannot confirm that this resolves our situation, but it may help you in yours.
I found 2 key things in my code that may help here:
On a logout event from my system, the background script would post a message that the frontend script would be listening for. To send this message, I ran a tabs query on all tabs.
chrome.tabs.query({ status: 'complete' }, (tabs) => {
tabs.forEach((tab) => {
chrome.tabs.sendMessage(tab.id, { event: 'logout', data: {} }, () => {});
});
});
- The first issue in my code, is that I never called the
sendResponse()
(I had just assumed that I didn't need it, so why call it), even though the onMessage
had return True
. The code was expecting an asynchronous response, but never received it, and would throw an error:
Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received
This error did not seem to have an real effect on the runtime or behaviour of my code, and I couldn't figure it out, so I ignored it.
- The second issue seems to have stemmed from the tabs query being on all tabs. In my manifest I limit my extension to only certain websites. This resulted in a second error:
uncaught (in promise) error: could not establish connection. receiving end does not exist.
Both of these errors take time to resolve (the timeout is something like 60 seconds) and during that time, the extension remained in the running state. If the user has many tabs open (like most people usually do), the extension would eventually get stuck in this perpetual running state.
Actions Taken
Here, I am not quite sure what is happening (whether there is or isn't a bug in Chrome), but it seems like after X period of time, the Chrome API listeners stop responding. As the extension never stops and restarts, there is no recovery of the listeners and the background script is forever stuck in this state. The extension icon works without an issue, but the main script is never executed. Only a restart of Chrome or the computer seems to resolve this.
I resolved the 2 issues by calling sendMessage()
in any place I have an onMessage
listener and by changing the tabs query to <all_urls>
which limits the query to the tabs that match the urls in the manifest, which removed the 2 errors. As a result, the extension now seems to have returned to the active/inactive cycle in the background script. On every wake up, the background script runs, reinitializing the alarms, if required, and resetting the listeners.
Hopefully this helps with this scenario. Best of luck!