Aller au contenu principal

Rollback, Kill-Switch et acquittement

TkushPatch intègre une chaîne complète de Rollback et Kill-Switch combinant la révocation serveur (manuelle ou par disjoncteur automatique), le retour arrière du moteur natif Rust sur le téléphone, le hook de nettoyage local du SDK tk_ota_push et l'acquittement d'incident (acknowledgeRollback) par les équipes Support N3 / SRE.

Vue d'ensemble du cycle de vie d'un Rollback​

Procédure de déclenchement du Rollback
  1. Détection de l'anomalie : Constat d'un dysfonctionnement critique sur un correctif publié.
  2. Neutralisation (Kill-Switch) : L'administrateur exécute tk-ota-push rollback ou clique sur Rollback dans la console.
  3. Désactivation serveur : Le statut passe à ROLLED_BACK et le taux de diffusion est ramené à 0%.
  4. Réaction des applications : Dès leur prochaine vérification, les terminaux révoquent le patch et repassent sur la version saine.

1. Déclencher le Kill-Switch d'un patch (ROLLED_BACK)​

La révocation d'un patch s'effectue en 1 clic depuis la Console Web ou en ligne de commande via l'API d'administration (OtaAdminController.rollbackPatch) :

curl -X POST "$OTA_SERVER_URL/api/admin/v1/patches/$PATCH_ID/rollback" \
-H "Authorization: Bearer $OTA_API_KEY"

Effets immédiats côté serveur (Serveur TkushPatch)​

  1. Le statut du patch passe à ROLLED_BACK et son rolloutPercentage est forcé à 0.
  2. Le cache L1/L2 de la Release est immédiatement invalidé (evictAllForRelease).
  3. Lors des appels suivants à /api/v1/patches/check, le numéro du patch figure dans la liste rolled_back_patch_numbers renvoyée au moteur natif Rust, qui désinstalle immédiatement le patch révoqué.
  4. Une entrée d'audit immuable PATCH_ROLLBACK_TRIGGERED est enregistrée sur le serveur.

Disjoncteur automatique (Circuit Breaker)​

Dans Serveur TkushPatch, le disjoncteur automatique est activé par défaut avec :

  • circuitBreakerMinSampleSize = 10 (au moins 10 événements télémétriques reçus pour ce patch)
  • circuitBreakerFailureRateThreshold = 0.05 (5 % de taux d'échec)

Si ce seuil est franchi, le serveur révoque automatiquement le patch sans attendre une intervention humaine.

2. Résilience côté application mobile (onRollbackDetected)​

Lorsqu'un appareil subit un rollback (par exemple du Patch #2 vers le Patch #1 ou vers le binaire Store d'origine null), un changement de schéma local (SQLite, Hive, SharedPreferences) introduit par le Patch #2 pourrait provoquer une erreur dans l'ancienne version restaurée.

La méthode verifyStartupAndHandleRollback() de TkOtaPush (appelée automatiquement au début de syncWithRemoteConfig) compare le patch en cours d'exécution avec le dernier patch enregistré par OtaRollbackTracker (current_patch < last_executed_patch) :

final ota = TkOtaPush.init(
appReleaseVersion: '1.0.0+3',
onRollbackDetected: (OtaRollbackEvent event) async {
debugPrint(
'Rollback détecté : #${event.previousPatchNumber} -> #${event.restoredPatchNumber}',
);
// Purger le cache local pour garantir la stabilité post-rollback
},
);

3. Acquittement d'un Rollback par appareil (acknowledgeRollback)​

Dans l'inventaire de flotte (GET /api/admin/v1/devices et Console Web /support), tout téléphone ayant remonté au moins un événement d'échec ou de rollback (failureCount > 0) apparaît avec l'indicateur rollbackTriggered: true (Rollback Actif).

Une fois l'incident résolu (par exemple après publication d'un nouveau patch correctif), l'opérateur peut acquitter l'alerte sans jamais altérer ni supprimer l'historique télémétrique immuable.

Règle d'évaluation exacte (OtaAdminController.listDiscoveredDevices)​

Le serveur stocke l'horodatage rollbackAcknowledgedAt dans ota_device_registry et évalue :

ackedAfterLastFailure = (rollbackAcknowledgedAt != null)
&& (latestFailureAt != null)
&& !rollbackAcknowledgedAt.isBefore(latestFailureAt)

rollbackTriggered = (failureCount > 0) && !ackedAfterLastFailure
  • Tant qu'aucun nouvel échec ne survient après rollbackAcknowledgedAt, l'appareil est comptabilisé comme Sain (rollbackTriggered: false, tandis que rawFailureDetected reste à true pour la traçabilité).
  • Si un nouvel échec survient sur un patch ultérieur (latestFailureAt > rollbackAcknowledgedAt), l'alerte rollbackTriggered: true se réactive automatiquement.

Commandes d'acquittement et de réinitialisation​

Vous pouvez cibler l'appareil par son UUID complet (client_id) ou le rechercher par son Code Court Support N3 (#6959347F, obtenu via ota.readShortSupportCode()) :

# 1. Acquitter l'alerte Rollback d'un appareil
curl -X POST "$OTA_SERVER_URL/api/admin/v1/devices/$CLIENT_ID" \
-H "Authorization: Bearer $OTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"acknowledgeRollback": true}'

# 2. Réinitialiser l'acquittement (remettre rollbackAcknowledgedAt à null)
curl -X POST "$OTA_SERVER_URL/api/admin/v1/devices/$CLIENT_ID" \
-H "Authorization: Bearer $OTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"resetRollbackAck": true}'