Búsqueda de sitios web

javascript - Los listeners de eventos de la extensión de Chrome V3 dejan de funcionar después de varios días


Actualmente estoy trabajando en el desarrollo de una extensión de Chrome y he notado que mi extensión funciona bien durante varios días o más, pero eventualmente llega a un estado en el que varios oyentes de eventos parecen dejar de funcionar. Por ejemplo, mi extensión escucha actualizaciones de almacenamiento provenientes de su popup y también una alarma que se activa cada minuto, pero en algún momento ambos parecen dejar de funcionar simultáneamente. Según puedo comprobar, mis oyentes de eventos están registrados de manera sincrónica, y continúan funcionando durante mucho más tiempo del que esperaría si no fuera así.

Además, cuando la extensión alcanza este estado, descubro que cuando agrego oyentes de eventos de prueba en la consola del service worker, estos oyentes tampoco parecen activarse correctamente.

No he podido identificar las circunstancias precisas bajo las cuales ocurre este problema, ni reproducirlo con éxito, excepto esperando varios días con mi extensión en funcionamiento. El problema no parece estar asociado con ninguna excepción en tiempo de ejecución. Si alguien ha experimentado un problema similar o tiene algún consejo de depuración, lo agradecería mucho. En este punto, no estoy seguro de cómo continuar investigando este problema.

Respuesta #1

He luchado con este problema recientemente y he visto esta pregunta publicada varias veces con respuestas o apoyo mínimos. Quería dar algunos comentarios sobre lo que descubrí en mi investigación y tal vez podría ser útil para ti.

Antecedentes:

Hace unos meses, comenzamos a recibir ocasionalmente quejas de algunos de los usuarios de que la extensión de Chrome ya no funcionaba. Esencialmente, los botones no se insertaban en su página web como se esperaba. Los usuarios podían iniciar sesión en nuestro sistema desde el ícono de la extensión, pero esto no activaba la ejecución de los scripts en la pestaña. La única manera de resolver el problema era reiniciando el navegador o la computadora.

La extensión registra varios alarmas, un oyente onTabUpdate y un oyente onMessage, ninguno de los cuales estaba respondiendo. Incluso al abrir las herramientas de desarrollo, no podía realizar ninguna acción, como enviar un mensaje, o incluso llamar a chrome.runtime.reload(), y no aparecían registros.

Un par de notas clave:

  1. El problema aparecería después de unos días de uso sin problemas
  2. No todos los usuarios experimentaron el problema
  3. Ocurrió a lo largo de múltiples versiones de la extensión

Investigación:

Usando chrome://serviceworker-internals, pude identificar que durante el comportamiento normal, la extensión entraba en un estado RUNNING cuando las alarmas se activaban o cuando la pestaña se cambiaba/abría y después de 30 segundos de inactividad, la extensión cambiaba a un estado STOPPED, pero volvería a entrar en el estado RUNNING cuando ocurría un evento o mensaje.

Hallazgos:

Dado que no puedo reproducir el problema por mi cuenta, no puedo confirmar que esto resuelva nuestra situación, pero puede ayudarte en la tuya.

Encontré 2 cosas clave en mi código que pueden ayudar aquí:

En un evento de cierre de sesión de mi sistema, el script de fondo enviaría un mensaje que el script de frontend estaría escuchando. Para enviar este mensaje, ejecuté una consulta de pestañas en todas las pestañas.

chrome.tabs.query({ status: 'complete' }, (tabs) => {
    tabs.forEach((tab) => {
        chrome.tabs.sendMessage(tab.id, { event: 'logout', data: {} }, () => {});
    });
});
  1. El primer problema en mi código es que nunca llamé a sendResponse() (simplemente había asumido que no lo necesitaba, así que ¿por qué llamarlo?), aunque onMessage tenía return True. El código esperaba una respuesta asíncrona, pero nunca la recibió, y lanzaría un error:
Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

Este error no parecía tener un efecto real en el tiempo de ejecución o en el comportamiento de mi código, y no pude resolverlo, así que lo ignoré.

  1. El segundo problema parece haberse originado porque la consulta de pestañas estaba en todas las pestañas. En mi manifiesto, limito mi extensión solo a ciertos sitios web. Esto resultó en un segundo error:
uncaught (in promise) error: could not establish connection. receiving end does not exist.

Ambos errores toman tiempo para resolverse (el tiempo de espera es algo así como 60 segundos) y durante ese tiempo, la extensión permaneció en estado de ejecución. Si el usuario tiene muchas pestañas abiertas (como usualmente la mayoría de las personas), la extensión eventualmente quedaría atascada en este estado de ejecución perpetua.

Acciones Realizadas

Aquí, no estoy muy seguro de lo que está sucediendo (si hay o no un error en Chrome), pero parece que después de un período de tiempo X, los escuchadores de la API de Chrome dejan de responder. Como la extensión nunca se detiene ni se reinicia, no hay recuperación de los escuchadores y el script de fondo queda atrapado para siempre en este estado. El ícono de la extensión funciona sin problema, pero el script principal nunca se ejecuta. Solo un reinicio de Chrome o del ordenador parece resolver esto.

Resolvió los 2 problemas llamando a sendMessage() en cualquier lugar donde tengo un listener onMessage y cambiando la consulta de pestañas a <all_urls>, lo que limita la consulta a las pestañas que coinciden con las URLs en el manifiesto, lo que eliminó los 2 errores. Como resultado, la extensión ahora parece haber vuelto al ciclo activo/inactivo en el script de fondo. En cada activación, el script de fondo se ejecuta, reinicializando las alarmas, si es necesario, y restableciendo los listeners.

Esperemos que esto ayude con este escenario. ¡Buena suerte!

Respuesta #2

Estaba teniendo el mismo problema y busqué por internet una respuesta pero sin suerte. Pero al final pude resolverlo por accidente.
La solución que me ayudó fue simplemente mover todas las asignaciones de listeners de las funciones hacia el flujo principal.

Antes:

chrome.runtime.onStartup.addListener(Init);

async function Init() {
    ...
    chrome.tabs.onActivated.addListener(__listener__);
    ...
}

Después:

chrome.runtime.onStartup.addListener(Init);
chrome.tabs.onActivated.addListener(__listener__);

async function Init() {
    ...
}

Mi suposición es que por alguna razón todas las acciones, procesos, variables (direcciones a las mismas) y cualquier otra asignación de memoria realizada en funciones se están borrando en el momento en que la Extensión se pone en reposo. Si estoy en lo correcto, esto lleva a que el evento intente ejecutar un listener que ya no existe en la memoria.

Artículos relacionados