web-dev-qa-db-fra.com

Comment puis-je supprimer un employé de service de buggy ou mettre en œuvre un "kill switch"?

Je joue avec l'API Service Worker sur mon ordinateur afin de comprendre comment en bénéficier dans mes applications du monde réel.

Je suis tombé sur une situation étrange où j'ai enregistré un travailleur de service qui intercepte l'événement fetch afin qu'il puisse vérifier son cache pour le contenu demandé avant d'envoyer une demande à l'origine. Le problème est que ce code a une erreur qui a empêché la fonction de faire la demande, donc ma page est laissée vierge; Rien ne se passe. Le technicien étant inscrit, la deuxième fois que je charge la page, il intercepte la toute première requête (celle qui charge le HTML). Parce que j'ai ce bogue, cet événement d'extraction échoue, il ne demande jamais le code HTML et tout ce que je vois est une page vierge.

Dans cette situation, la seule façon dont je sais supprimer le mauvais script de service worker est par le biais de chrome://serviceworker-internals/ console. Si cette erreur arrive sur un site Web en direct, quelle est la meilleure façon de la résoudre?

Merci!

44
PaquitoSoft

Je voulais développer certaines des autres réponses ici, et aborder cela du point de vue de "quelles stratégies puis-je utiliser lors du déploiement d'un technicien de service en production pour m'assurer que je peux apporter les modifications nécessaires"? Ces changements peuvent inclure la correction de bogues mineurs que vous découvrez en production, ou cela peut (mais, espérons-le, pas) inclure la neutralisation du technicien de service en raison d'un bogue insurmontable - un soi-disant "kill switch".

Aux fins de cette réponse, supposons que vous appelez

navigator.serviceWorker.register('service-worker.js');

sur vos pages, ce qui signifie que la ressource JavaScript de votre technicien de service est service-worker.js. ( Voir ci-dessous si vous n'êtes pas sûr de l'URL exacte du service worker qui a été utilisée, peut-être parce que vous avez ajouté un hachage ou des informations de version au script du service worker.)

La question se résume à la façon dont vous allez résoudre le problème initial dans votre code service-worker.js. Si c'est une petite correction de bogue, alors vous pouvez évidemment faire le changement et redéployer votre service-worker.js vers votre environnement d'hébergement. S'il n'y a pas de correction de bogue évidente et que vous ne voulez pas laisser vos utilisateurs exécuter le code de l'ouvrier du service de bogue pendant que vous prenez le temps de trouver une solution, c'est une bonne idée de simple, no-opservice-worker.js handy , comme le suivant:

// A simple, no-op service worker that takes immediate control.

self.addEventListener('install', () => {
  // Skip over the "waiting" lifecycle state, to ensure that our
  // new service worker is activated immediately, even if there's
  // another tab open controlled by our older service worker code.
  self.skipWaiting();
});

/*
self.addEventListener('activate', () => {
  // Optional: Get a list of all the current open windows/tabs under
  // our service worker's control, and force them to reload.
  // This can "unbreak" any open windows/tabs as soon as the new
  // service worker activates, rather than users having to manually reload.
  self.clients.matchAll({type: 'window'}).then(windowClients => {
    windowClients.forEach(windowClient => {
      windowClient.navigate(windowClient.url);
    });
  });
});
*/

Cela devrait être tout ce que votre no-op service-worker.js doit contenir. Puisqu'il n'y a pas de gestionnaire fetch enregistré, toutes les demandes de navigation et de ressources des pages contrôlées finiront par aller directement contre le réseau, vous donnant effectivement le même comportement que vous obtiendriez sans s'il n'y avait aucun travailleur de service.

Étapes supplémentaires

Il est possible d'aller plus loin et de supprimer de force tout ce qui est stocké à l'aide de Cache Storage API , ou de désinscrire explicitement le service worker entièrement. Dans la plupart des cas, cela va probablement être exagéré, et suivre les recommandations ci-dessus devrait être suffisant pour vous mettre dans un état où vos utilisateurs actuels obtiennent le comportement attendu, et vous êtes prêt à redéployer les mises à jour une fois que vous avez corrigé vos bogues . Il y a un certain degré de surcharge lié au démarrage même d'un travailleur de service sans opération, vous pouvez donc suivre la voie désenregistrement du travailleur de service si vous n'avez pas l'intention de redéployer un code de travailleur de service significatif.

Si vous êtes déjà dans une situation dans laquelle vous servez service-worker.js avec des directives de mise en cache HTTP lui donnant une durée de vie plus longue que ce que vos utilisateurs peuvent attendre, gardez à l'esprit qu'un Shift + Reload sur les navigateurs de bureau forcera la page à se recharger en dehors du contrôle du technicien de service. Tous les utilisateurs ne sauront pas comment procéder, et ce n'est pas possible sur les appareils mobiles. Ne comptez donc pas sur Shift + Reload comme plan de restauration viable.

Que faire si vous ne connaissez pas l'URL du technicien de service?

Les informations ci-dessus supposent que vous connaissez l'URL du technicien de service —service-worker.js, sw.js, ou quelque chose d'autre qui est effectivement constant. Mais que se passe-t-il si vous incluez une sorte d'informations de version ou de hachage dans votre script de service worker, comme service-worker.abcd1234.js?

Tout d'abord, essayez d'éviter cela à l'avenir — c'est contre les meilleures pratiques . Mais si vous avez déjà déployé un certain nombre d'URL de service worker versionné et que vous devez désactiver les choses pour les utilisateurs tous, quelle que soit l'URL qu'ils ont pu enregistrer, il existe un moyen de sortir.

Chaque fois qu'un navigateur effectue une demande de script de service worker, qu'il s'agisse d'un enregistrement initial ou d'une vérification de mise à jour, il définit un en-tête de demande HTTP appelé Service-Worker: .

En supposant que vous ayez un contrôle total sur votre serveur HTTP principal, vous pouvez vérifier les demandes entrantes pour la présence de cet en-tête Service-Worker: et toujours répondre avec votre réponse de script de travailleur de service sans opération, quelle que soit l'URL de la demande .

Les spécificités de la configuration de votre serveur Web pour ce faire varient d'un serveur à l'autre.

L'en-tête Clear-Site-Data: réponse

Une dernière remarque: certains navigateurs effaceront automatiquement des données spécifiques et éventuellement annuler l'enregistrement des travailleurs du service lorsqu'un en-tête de réponse HTTP spécial est renvoyé dans le cadre de toute réponse: Clear-Site-Data: .

La définition de cet en-tête peut être utile lorsque vous tentez de récupérer après un mauvais déploiement de service worker, et des scénarios de kill-switch sont inclus dans la fonctionnalité spécification comme exemple d'utilisation.

Il est important de vérifier histoire de support du navigateur pour Clear-Site-Data: avant de vous y fier uniquement dessus comme un kill-switch. Depuis juillet 2019, il n'est pas pris en charge dans 100% des navigateurs qui prennent en charge les employés de service, donc pour le moment, il est plus sûr d'utiliser Clear-Site-Data: avec les techniques mentionnées ci-dessus si vous souhaitez vous remettre d'un travailleur du service défectueux dans tous les navigateurs.

70
Jeff Posnick

C'est une situation vraiment désagréable, qui, je l'espère, ne vous arrivera pas en production.

Dans ce cas, si vous ne souhaitez pas passer par les outils de développement des différents navigateurs, chrome://serviceworker-internals/ pour les navigateurs basés sur le clignotement, ou about:serviceworkers (about:debugging#workers à l'avenir) dans Firefox, deux choses me viennent à l'esprit:

  1. Utilisez le mécanisme de mise à jour de Serviceworker. Votre agent utilisateur vérifiera s'il y a un changement sur le travailleur enregistré, le récupérera et passera à nouveau par la phase activate. Vous pouvez donc potentiellement changer le script de serviceworker, corriger (purger les caches, etc.) toute situation étrange et continuer à travailler. Le seul inconvénient est que vous devrez attendre que le navigateur mette à jour le travailleur, ce qui pourrait être 1 jour.
  2. Ajoutez une sorte de kill switch à votre travailleur. Avoir une URL spéciale où vous pouvez pointer les utilisateurs à visiter qui peut restaurer le statut de vos caches, etc.

Je ne sais pas si l'effacement des données de votre navigateur supprimera le travailleur, ce qui pourrait être une autre option.

8
Francisco Jordano

Vous pouvez "désinscrire" le technicien de service à l'aide de javascript. Voici un exemple:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.getRegistrations().then(function (registrations) {
    //returns installed service workers
    if (registrations.length) {
      for(let registration of registrations) {
        registration.unregister();
      }
    }
  });
}
5
Prasanna Jathan

Pour les situations réelles, vous devez modifier le technicien de service au niveau octet (mettez un commentaire sur la première ligne, par exemple) et il sera mis à jour dans les prochaines 24 heures . Vous pouvez émuler cela avec le bouton chrome: // serviceworker-internals/in Chrome en cliquant sur Mettre à jour le bouton ).

Cela devrait fonctionner même dans les situations où le travailleur de service lui-même a été mis en cache lorsque l'étape 9 de l'algorithme de mise à jour a défini un indicateur pour contourner le travailleur de service.

3
Salva

Je n'ai pas testé cela, mais il existe une méthode nregister () et pdate () sur l'objet ServiceWorkerRegistration. vous pouvez l'obtenir auprès de navigator.serviceWorker.

navigator.serviceWorker.getRegistration('/').then(function(registration) {
  registration.update();
});

la mise à jour devrait alors immédiatement vérifier s'il y a un nouveau technicien de service et si oui l'installer. Cela contourne la période d'attente de 24 heures et téléchargera le serviceworker.js chaque fois que ce javascript est rencontré.

3
Marco Tolk