MV3 ServiceWorker implementation is completely unreliable

1,353 views
Skip to first unread message

guest271314

unread,
May 27, 2021, 1:08:28 PM5/27/21
to Chromium Extensions
Currently the MV3 ServiceWorker implementation becomes inactive in 5 minutes.

To reproduce unreliability of current Chrome/Chromium implementation of ServiceWorker we create a Native Messaging extension, post a message to ServiceWorker at origin listed in "externally_connectable", wait more than 5 minutes to post another message to ServiceWorker from externally connectable. The port externally connectable port becomes disconnected in 5 minutes.

This broken implementation appears to be easily fixable by providing a user option, e.g., 

{
  "background": {
    "service_worker": "background.js",
    "service_worker_becomes_inactive": false
  },
}

or similar mechanism to instruct the extension to not become "inactive" after whatever arbitrary time the source evidently currently has hard-coded.

Without mitigation, that is, inaction re this matter, the MV3 ServiceWorker implementation shall remain absolutely unreliable, and broken, for no apparent reason.

Screenshot_2021-05-27_09-28-32.png
Screenshot_2021-05-27_09-53-40.png

Cuyler Stuwe

unread,
May 27, 2021, 1:11:36 PM5/27/21
to guest271314, Chromium Extensions
Yeah, this has been posted a few times and is basically the most glaring flaw of all of MV3’s flaws so far.

Major major major gaping hole. Must-fix.

--
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/1420842e-cc82-42c8-bea8-7037e3791cd2n%40chromium.org.

guest271314

unread,
May 27, 2021, 1:24:43 PM5/27/21
to Chromium Extensions, salem...@gmail.com, Chromium Extensions, guest271314
This appears to be very fixable.

I do not sense any urgency to fix the bug.

I filed https://bugs.chromium.org/p/chromium/issues/detail?id=1115640 and https://groups.google.com/a/chromium.org/g/chromium-extensions/c/BnsgStmVOMc/m/7E0mXxI-AAAJ here for the purpose of highlighting issues with the now-archaic technology used for both postMessage() from "externally_connectable", and between Native Messaging host and background extension (JSON https://bugs.chromium.org/p/chromium/issues/detail?id=248548).

Chrome/Chromium has implemented and deprecated QuicTransport in the interim, which could be used for communication between host and background extension and background extension and Window. Transferable Stream is also implemented at Chrome/Chromium, which can also be used instead of passing JSON back and forth.

In the meantime since MV3 is broken and unreliable for Native Messaging and Native Messaging and extension messaging are both not using streams, I wrote the specification for and implemented  NativeTransferableStreams myself, using Transferable Streams https://github.com/guest271314/NativeTransferableStreams.

The only possible impediments I observe as to reasoning for not updating the relevant API's and addressing these glaring issues is lack of will to do so, or inability of Chromium/Chrome authors to access constructive feedback from users at large which demonstrate the facts that their API designs are ill-conceived and broken. 

hrg...@gmail.com

unread,
May 27, 2021, 3:27:14 PM5/27/21
to Chromium Extensions, guest...@gmail.com, salem...@gmail.com, Chromium Extensions
The people behind MV3 are fixated with making the service worker ephemeral. There's zero chance they'll add any option to make it persistent. That would go against their whole preaching.

I have no idea how they plan to fix persistent Port connections.
If the service worker is shutdown when a Port connection is active, they could keep the port connection alive internally, but then when the service worker wakes up, how are we going to re-attach the event listeners to that Port?
In order to get another Port object, we must call the corresponding API function again. But that will create a new connection. What we need instead is to get a port object for existing connections.

They only solution I see (if they want to keep the SW ephemeral) is to change the API by removing the concept of a port and replacing it with a "connection ID" (a string) which is passed to a global event listener.

That way, event listeners can be registered again and again on every wake up of the SW.

Darbid Darbid

unread,
May 27, 2021, 3:37:08 PM5/27/21
to Chromium Extensions, hrg...@gmail.com, guest...@gmail.com, salem...@gmail.com, Chromium Extensions
The people behind MV3 will not change anything. If I were a betting person, then I would bet the whole chrome team were given targets to put a memory hungry, obscenely obese Google Chrome on a diet. The extensions team got their target of memory reduction and got their Christmas bonus but pulling the rug from under the feet of all developers by removing background functionality, meaning that extensions could no longer have things sitting around in memory.

And it is not going to change because Google Chrome is already spooking/advertising about its reduction in memory footprint.

guest271314

unread,
May 27, 2021, 6:57:53 PM5/27/21
to Chromium Extensions, maild...@gmail.com, hrg...@gmail.com, guest271314, salem...@gmail.com, Chromium Extensions
I need not add to the prima facie evidence already on the record re Chromium/Chrome selectively marking issues, both existing and feature requests as WontFix; inaction with regard to obvious bugs; or even coloring obvious bugs as features.

In coding my objective is simple: Fix WontFix.Screenshot_2021-05-28_00-51-16.png

One workaround for keeping ServiceWorker from becoming "inactive" and maintaining a persistent connection to the same Native Messaging host is using the event loop Concurrency model and the event loop https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop.

"A service worker is said to be running if its event loop is running."


"The lifetime of a service worker is tied to the execution lifetime of events ..."

2.1.2. Events https://w3c.github.io/ServiceWorker/#service-worker-events

"The Service Workers specification defines service worker events (each of which is an event) that include (see the list):


keepAlive.js

async function* keepAlive() {
  while (true) {
    if (chrome.runtime.lastError) {
      console.log(chrome.runtime.lastError);
      port.disconnect();
      nativeMessaginPort.disconnect();
      break;
    }
    yield new Promise((resolve, reject) => {
      setTimeout(
        () =>
          resolve(
            `ServiceWorker still alive at ${
              (new Date().getTime() - t) / 1000 / 60
            }`
          ),
        1000 * 60 * 4.9
      );
    });
  }
}

async function eventDriven() {
  for await (const _ of keepAlive()) {
    console.log(_);
  }
}

background.js

const hostName = 'native_messaging';
importScripts('./keepAlive.js');
const t = new Date().getTime();
let port;
const nativeMessagingPort = chrome.runtime.connectNative(hostName);
nativeMessagingPort.onDisconnect.addListener(async () => {
  console.log('Disconnected', nativeMessagingPort);
});
self.onfetch = async (e) => {
  console.log(e);
};
console.log(nativeMessagingPort);
chrome.runtime.onInstalled.addListener(async () => {
  console.log(self);
  eventDriven();
});
chrome.runtime.onConnectExternal.addListener((_) => {
  port = _;
  nativeMessagingPort.onMessage.addListener((message) => {
    port.postMessage(message);
    console.log(message);
  });
  port.onMessage.addListener(async (message) => {
    if (message.disconnect) {
      nativeMessagingPort.disconnect();
      port.disconnect();
      return;
    }
    nativeMessagingPort.postMessage(message);
    console.log(message);
  });
});

Web page

function sendMessage() {
  return { message: `MV3 ServiceWorker test at ${new Date()}` };
}
var timer;
var disconnected = false;
var id = 'jmnojflkjiloekecianpibbbclcgmhag';
var port = chrome.runtime.connect(id);
port.onMessage.addListener((e) => {
  console.log(e);
  timer = setTimeout(() => {
    port.postMessage(sendMessage());
  }, 1000 * 60 * 6);
});
port.onDisconnect.addListener((e) => {
  disconnected = true;
  clearTimeout(timer);
  console.log(e);
});
port.postMessage(sendMessage());
Reply all
Reply to author
Forward
Message has been deleted
0 new messages