Les frameworks modernes de mitigation de bots (Cloudflare Turnstile, DataDome, Akamai Bot Manager, Shape Security) et les moteurs d'évaluation des risques de paiement (Sift, Riskified, Stripe Radar) ont radicalement fait évoluer leurs paradigmes. Ils ne se contentent plus de consulter des listes de blocage d'adresses IP statiques. Aujourd'hui, ils analysent la continuité d'état (state continuity) tout au long du cycle de vie d'un parcours utilisateur.

Lors du scraping d'applications monopages complexes (SPA) ou de l'automatisation de tunnels d'achat multi-étapes (multi-step checkouts), décider d'effectuer une rotation d'IP ou de maintenir une session persistante (stickiness) ne relève pas d'un simple ajustement opérationnel. Il s'agit d'un choix architectural déterminant : c'est la différence entre des transactions finalisées avec succès et des sessions purgées silencieusement par les moteurs anti-fraude.

       TUNNEL D'ACHAT MULTI-ÉTAPES TYPIQUE & RISQUES D'INVALIDATION D'ÉTAT
       
+---------------+     +---------------+     +---------------+     +---------------+
| 1. Auth/Login | --> | 2. Panier/Cart| --> | 3. Livraison  | --> | 4. Stripe/3DS |
+---------------+     +---------------+     +---------------+     +---------------+
  Session TCP 1         Session TCP 2         Session TCP 3         Session TCP 4
  TLS: Client JA4       TLS: Client JA4       TLS: Client JA4       TLS: Client JA4
  IP: 185.24.xx.1       IP: 185.24.xx.1       IP: 92.40.xx.88       IP: 92.40.xx.88
                                                     ^
                                     [ DÉCONNEXION DU PAIR RÉSIDENTIEL ]
                                     - Saut d'IP : Rupture d'ASN
                                     - Invalidation du TLS Ticket
                                     - PIC DU SCORE DE FRAUDE -> HTTP 403

1. Synthèse Exécutive & Le Problème des Ruptures de Session en Plein Tunnel

En ingénierie d'automatisation réseau, une tension structurelle oppose constamment l'anonymat par la rotation et l'intégrité de l'état par la persistance :

  • Proxys rotatifs : Conçus pour contourner le rate-limiting sur des endpoints sans état (stateless) à haut débit (pagination de recherche, indexation de catalogues publics, moissonnage de données ouvertes).
  • **Sessions persistantes (sticky) :** Indispensables dès que la couche applicative maintient un état sur plusieurs requêtes HTTP via des cookies, du cache en mémoire côté serveur (sessions Redis/Memcached), des tickets de session TLS ou des jetons de sécurité (jetons porteurs OAuth2, jetons CSRF, PaymentIntents Stripe).

La rupture se produit lorsque les développeurs tentent d'exécuter des actions avec état via des réseaux de proxys résidentiels partagés d'entrée de gamme. Ces derniers promettent commercialement des sessions persistantes de « 10 minutes » ou « 30 minutes ». Dans la réalité technique, ces réseaux routent le trafic à travers des nœuds grand public pair-à-pair (P2P) éphémères : smartphones infectés, téléviseurs connectés monétisés via des SDK tiers ou box Internet domestiques.

Dès que le propriétaire du terminal sort du rayon Wi-Fi, referme son ordinateur portable ou que le système d'exploitation déclenche une mise en veille agressive de la batterie, la connexion TCP sous-jacente est brutalement interrompue. La passerelle backconnect du fournisseur de proxy intercepte le socket fermé et réassigne immédiatement votre requête à une toute nouvelle adresse IP résidentielle.

Pour un moteur de détection de fraude, observer un changement d'adresse IP entre un appel POST /cart/checkout et un appel POST /api/v1/payment_intents constitue un indicateur immédiat de détournement de session (session hijacking). La transaction est instantanément avortée, la réservation de stock est libérée et l'empreinte logicielle (browser fingerprint) est définitivement blacklistée.


2. L'Anatomie d'un Échec d'Achat (Checkout Drop)

Pour appréhender pourquoi les mutations d'IP en cours de navigation s'avèrent fatales aux tunnels d'achat et aux machines à états authentifiées, analysons la télémétrie réseau d'une transaction réelle.

===================================================================================
TRACÉ ÉTAPE PAR ÉTAPE D'UN TUNNEL : MUTATION DE TÉLÉMÉTRIE RÉSEAU
===================================================================================
Étape 1 : Authentification (POST /api/auth/login)
  - IP Client : 80.12.45.112 (Orange France, AS12479)
  - En-têtes : Set-Cookie: __Secure-SessionId=a8f9b...; Domain=.cible.com; Secure; HttpOnly
  - Empreinte TLS (JA4) : t13d1516h2_8daaf6152771_b186095e22b6
  - Moteur de Risque : Empreinte de référence enregistrée. Score de Risque : 12/100 (Succès).

Étape 2 : Réservation d'Inventaire (POST /checkout/reserve)
  - IP Client : 80.12.45.112 (Cohérente)
  - En-têtes : Cookie: __Secure-SessionId=a8f9b...
  - Backend : Redis mappe SessionId -> Panier : [SKU-89211], TTL de verrouillage : 420s.

Étape 3 : Saisie d'Adresse & Calcul des Taxes (POST /checkout/shipping)
  - [PAIR RÉSIDENTIEL HORS LIGNE - ROTATION FORCÉE DU BACKCONNECT]
  - IP Client : 176.159.201.44 (Free SAS, AS12322) [MUTATION ANORMALE]
  - GeoIP : Déplacement Lat/Long de 48.8566, 2.3522 (Paris) à 43.6047, 1.4442 (Toulouse)
  - Vitesse Réseau : 680 km/h calculés sur un intervalle de 450 ms.
  - Moteur de Risque : Alerte déclenchée : Anomalie de géo-vélocité. Score : 68/100.

Étape 4 : Tokenisation du Paiement (POST https://api.stripe.com/v1/tokens)
  - IP Client : 176.159.201.44 (Free SAS)
  - Requête : Transmission des données bancaires + Empreinte Stripe Radar.
  - Vérification : Stripe détecte une divergence d'IP entre l'IP d'initiation du panier 
    chez le marchand (Orange) et l'IP de tokenisation de la carte (Free).
  - Intervention Anti-Fraude : Riskified / Sift évalue le delta de session :
    * Delta IP : VRAI
    * Delta ASN : VRAI (AS12479 -> AS12322)
    * Échec de reprise TLS : Le client a émis un nouveau ClientHello sans Session Ticket valide.
  - Résultat : HTTP 402 Card Declined / HTTP 403 Forbidden. Compte banni discrètement (Shadowban).
===================================================================================

Le Mécanisme de Détection des Moteurs Anti-Fraude

Lorsqu'une adresse IP mute au milieu d'un processus critique, les heuristiques de détection appliquent des contrôles stricts :

1. Vecteurs de Géo-Vélocité (Contrôles de Vitesse Impossible)

Si la Requête N provient de Paris à l'instant $T_1$, et que la Requête N+1 émane de Lyon à l'instant $T_2$, l'algorithme calcule la vitesse cinématique théorique de l'utilisateur :

$$V = \frac{\text{Haversine}(Loc_1, Loc_2)}{T_2 - T_1}$$

Si $V > 900\text{ km/h}$, la requête est instantanément bloquée, étant assimilée à un vol de session ou à un relais non maîtrisé via proxy.

2. Invalidation du Cache de Session TLS

Lors de l'établissement d'une liaison sécurisée, TLS 1.3 s'appuie sur des Session Tickets (NewSessionTicket) pour autoriser une reprise rapide à latence réduite (0-RTT/1-RTT). Si la passerelle de proxy change silencieusement le pair sous-jacent, le nouveau nœud distant est dans l'incapacité de reprendre l'état TLS négocié par le précédent. Le serveur distant constate alors soit une renégociation TLS complète, soit un handshake initial provenant d'une IP inconnue mais porteuse d'un cookie de session préexistant. Cette désynchronisation élève immédiatement le score d'anomalie au sein des WAF comme DataDome ou Akamai.

3. Corrélation IP Marchand / Passerelle de Paiement

Les passerelles bancaires comme Stripe Radar, Adyen ou Braintree croisent en temps réel l'IP du client final soumettant le formulaire bancaire avec l'IP ayant initié la commande sur le serveur applicatif marchand. Une discordance de système autonome (ASN) déclenche systématiquement un défi 3D-Secure (3DS) renforcé, voire un rejet pur et simple de l'autorisation de débit, entraînant un signalement négatif sur l'émetteur de la carte (BIN).


3. Pourquoi les Proxys Résidentiels « Sticky » Échouent Inévitablement

La quasi-totalité des acteurs commerciaux du proxy mettent en avant des « IP résidentielles sticky » avec une promesse de persistance théorique allant de 10 à 60 minutes. D'un point de vue strict d'ingénierie réseau, cette promesse relève de l'illusion technique.

       LA FRAGILITÉ STRUCTURELLE DES RÉSEAUX RÉSIDENTIELS
       
+------------------------+
| Script d'Automatisation|
+------------------------+
            |
            | (Requête HTTP standard)
            v
+--------------------------------------------------------+
| Load Balancer Backconnect du Fournisseur               |
| (Maintient la table de routage : ?session_id=node_01)  |
+--------------------------------------------------------+
            |
            +-----------------------+
            |                       |
            v (Tunnel TCP)          v (Bascule sur panne)
+-----------------------+   +-----------------------+
| Pair Résidentiel A    |   | Pair Résidentiel B    |
| (PC portable étudiant |   | (TV connectée dans    |
| sur Wi-Fi via SDK)    |   | une autre ville)      |
+-----------------------+   +-----------------------+
      | (Fermeture capot)         |
      X [SOCKET ROMPU]            v (Nouvelle IP imposée)
                                Serveur Cible / WAF

Les réseaux résidentiels reposent sur la monétisation applicative via des SDK intégrés à des logiciels gratuits, des VPN grand public ou des extensions de navigateur. En conséquence, le fournisseur de proxy ne détient ni le matériel, ni le lien réseau, ni la maîtrise du cycle d'alimentation du nœud de terminaison.

Points de Défaillance Inhérents aux Nœuds Résidentiels

  • Expiration de Bail DHCP et Itinérance Wi-Fi : Les terminaux grand public basculent fréquemment entre les bandes de fréquences ou de la 4G/5G vers le réseau Wi-Fi local. Chaque renégociation radio rompt le socket TCP et entraîne l'attribution d'une nouvelle adresse IP publique.
  • Gestion Énergétique des Systèmes d'Exploitation : Les mécanismes d'économie d'énergie (Doze Mode sous Android, gel des processus d'arrière-plan sous iOS/macOS) coupent l'accès réseau des applications tierces entre 10 et 60 secondes après le verrouillage de l'écran.
  • Redémarrages et Ruptures Matérielles : Les ordinateurs personnels sont mis en veille, débranchés du secteur ou déplacés physiquement sans préavis, fermant unilatéralement les connexions actives.
  • Réattribution Opaque par la Passerelle : Les répartiteurs backconnect sondent en permanence la santé des pairs via des paquets ICMP ou des pings TCP. Dès que le Pair A cesse de répondre, le répartiteur redirige votre session_id vers le Pair B. Vous ne recevez aucun message d'erreur d'infrastructure : votre requête subit une mutation d'IP silencieuse et fatale pour votre session en cours.

Comparatif Réseau : Passerelle Résidentielle vs Passerelle Cellulaire Dédiée

Propriété Réseau / TélémétriePasserelle Résidentielle PartagéePasserelle 5G Dédiée (Proxym)Impact sur les Tunnels d'Achat
Point de Terminaison PhysiqueTerminal grand public (PC/Mobile/IoT)Modem industriel 5G (Teltonika RUTX50)Taux de panne élevé vs Disponibilité de 99,9 %
Maîtrise de la LiaisonEmpruntée / P2P volatileCarte SIM d'entreprise dédiéeRuptures subies vs Contrôle total par l'utilisateur
Durée Réelle de Session2 à 12 minutes (Aléatoire)Illimitée (Heures, Jours, Semaines)Déterminant : Les tunnels longs aboutissent
Déclenchement de RotationPanne du nœud ou bascule de chargeAppel d'API REST déterministeAucune mutation imprévue en pleine transaction
Typologie Réseau (ASN)FAI Fixe grand public / ADSL / FibreOpérateurs Mobiles Majeurs (Orange, SFR, Free, Bouygues)Le CGNAT mobile bénéficie du niveau de confiance le plus élevé
Modèle de FacturationFacturation au Go (Coûteux : 8 € à 15 €/Go)Forfait fixe mensuel (80 €/port, 200 Go Fair Use)Les transferts lourds ne dégradent pas la rentabilité

4. La Garantie du Matériel Dédié

Pour obtenir une persistance de session sans faille, la couche physique doit être totalement découplée des aléas des équipements domestiques. Cela implique l'utilisation d'équipements de routage industriels, associés à des forfaits mobiles professionnels non partagés.

       ARCHITECTURE DE PROXY CELLULAIRE INDUSTRIEL DÉDIÉ
       
 [ Worker d'Automatisation ] 
              |
              | Authentification HTTP Connect / SOCKS5
              v
 +-----------------------------------------------------------------------+
 | INFRASTRUCTURE PROXYM                                                 |
 |                                                                       |
 |   +---------------------------------------------------------------+   |
 |   | Passerelle Industrielle Teltonika (RUTX50 / TRB500)           |   |
 |   | - SIM Dédiée Entreprise (Orange / SFR / Bouygues / Free)      |   |
 |   | - Module Modem 5G Industriel Quectel                          |   |
 |   | - Session PDP Maintenue en Continu avec l'Opérateur           |   |
 |   +---------------------------------------------------------------+   |
 |                                   |                                   |
 |                     Hook d'API Matériel Déterministe                  |
 |                 POST /api/proxies/{assignmentId}/rotate               |
 +-----------------------------------|-----------------------------------+
                                     |
                                     v (Tunnel GTP-U / 5G SA Bearer)
 +-----------------------------------------------------------------------+
 | CŒUR DE RÉSEAU OPÉRATEUR TIER-1 (POOL CGNAT MOBILE)                   |
 |                                                                       |
 |   IP Publique : 80.12.35.198 (Partagée avec des milliers de mobiles)  |
 |   Évaluation WAF : « Connexion Cellulaire Légitime »                  |
 +-----------------------------------------------------------------------+
                                     |
                                     v
                           [ Plateforme Web Cible ]

La Couche Réseau Cellulaire : Contexte PDP et Porteurs EPS

À l'inverse des connexions filaires soumises au renouvellement de bail DHCP local, les modems cellulaires s'interfacent avec le cœur de réseau télécoms (Evolved Packet Core / 5G Core) au moyen de tunnels de données persistants :

  • Contexte PDP (Packet Data Protocol) : Lors de son initialisation, le modem physique négocie un contexte PDP avec la passerelle de l'opérateur (GGSN ou UPF en 5G).
  • Encapsulation GTP : Les paquets de données sont encapsulés au sein d'un tunnel GTP-U (GPRS Tunneling Protocol User Plane). L'adresse IP publique attribuée en sortie du CGNAT (Carrier-Grade NAT) de l'opérateur mobile reste rigoureusement verrouillée sur ce support radio tant que l'interface réseau n'est pas réinitialisée explicitement par une séquence de commandes cellulaires (commandes normalisées de type AT+CFUN).

Proxym utilise des routeurs et modems industriels haut de gamme (séries Teltonika RUTX50 et TRB500) hébergeant des cartes SIM d'entreprise reliées aux opérateurs français de premier rang (Orange, SFR, Bouygues Telecom, Free Mobile).

Cette architecture réseau offre deux garanties techniques fondamentales :

  1. **Persistance Absolue (Infinite Stickiness) :** L'adresse IP ne change jamais arbitrairement au bout de 5, 10 ou 30 minutes. Elle demeure inchangée aussi longtemps que votre pipeline le requiert : des heures, des jours, ou la totalité d'un processus multi-étapes.
  2. Rotation Déterministe : La rotation intervient uniquement sur ordre de votre infrastructure, via un appel sécurisé à l'API REST (POST /api/proxies/{assignmentId}/rotate). Le matériel réinitialise alors la couche radio au niveau bas, forçant l'opérateur télécom à délivrer une nouvelle IP mobile depuis son pool CGNAT en quelques secondes.

Démonstration Mathématique : Probabilité de Maintien de Session

Nous pouvons modéliser la probabilité qu'une session d'automatisation aille à son terme sans subir de rupture d'IP imprévue à l'aide d'une fonction de fiabilité $R(t)$.

Sur un réseau résidentiel pair-à-pair, les déconnexions suivent un processus de Poisson non homogène, où la probabilité de perte du nœud croît exponentiellement avec la durée de l'opération $t$ :

$$R_{\text{residentiel}}(t) = e^{-\lambda t}$$

Où $\lambda$ représente le taux de défaillance instantané du nœud (induit par les coupures de signal, les mises en veille et la mobilité). Les benchmarks de terrain révèlent une demi-vie moyenne d'un nœud résidentiel $t_{1/2} \approx 420\text{ secondes}$ ($\lambda \approx 0{,}00165$).

Dès lors, la probabilité de succès d'un tunnel d'achat de 8 étapes d'une durée de 6 minutes (360 secondes) est de :

$$R_{\text{residentiel}}(360) = e^{-0{,}00165 \times 360} = e^{-0{,}594} \approx 55{,}2\%$$

Près d'une transaction sur deux échouera en production pour cause de rupture d'IP.

À l'inverse, avec un modem 5G industriel dédié sur alimentation secourue, le taux de défaillance résiduel est corrélé au MTBF (temps moyen entre pannes) du matériel industriel. Le risque de coupure inopinée sur les fenêtres d'exécution applicatives devient quasi nul :

$$R_{\text{dedie}}(t) \approx 0{,}9998 \quad \forall \; t \in [0, 86400\text{ secondes}]$$


5. Patterns Opérationnels : Quand Rester Sticky vs. Quand Faire Tourner

Une architecture d'automatisation robuste doit être pensée comme une machine à états finis déterministe. Alterner d'IP de façon désordonnée entraîne le blocage des comptes clients ; maintenir une IP indéfiniment sature vos seuils de requêtes et expose votre pipeline aux restrictions de volume.

+------------------------------------------------------------------------------------+
|                PATTERN D'ARCHITECTURE : MACHINE À ÉTATS POUR L'AUTOMATISATION      |
+------------------------------------------------------------------------------------+

  [ Initialisation du Worker ]
              |
              v
+-----------------------------+
| Contrôle Santé Port Proxy   | <--------------------------------------------+
+-----------------------------+                                              |
              |                                                              |
              v                                                              |
+-----------------------------+                                              |
| 1. PHASE DE CHAUFFE (WARMUP)|                                              |
| - IP Persistante (Sticky)   |                                              |
| - Chargement cookies, nav.  |                                              |
+-----------------------------+                                              |
              |                                                              |
              v                                                              |
+-----------------------------+                                              |
| 2. TUNNEL D'ACHAT (CHECKOUT)|                                              |
| - IP Strictement Identique  |                                              |
| - Tokenisation, Paiement    |                                              |
+-----------------------------+                                              |
              |                                                              |
              +-----------------------+                                      |
              |                       |                                      |
     (Transaction Validée)      (Échec Critique / Blocage)                    |
              |                       |                                      |
              v                       v                                      |
+-----------------------------+   +------------------------------------+     |
| 3. LOGS & TÉLÉMÉTRIE        |   | 3b. ISOLATION DU PROFIL            |     |
| - Extraction de commande    |   | - Purge cookies, révocation jeton  |     |
+-----------------------------+   +------------------------------------+     |
              |                                  |                           |
              +-------------------+--------------+                           |
                                  |                                          |
                                  v                                          |
                  +-------------------------------+                          |
                  | 4. APPEL DE ROTATION API      |                          |
                  | POST /api/proxies/.../rotate  |                          |
                  +-------------------------------+                          |
                                  |                                          |
                                  v                                          |
                  +-------------------------------+                          |
                  | 5. RECONNEXION NOUVEAU PDP    |                          |
                  | - Polling /health opérationnel| -------------------------+
                  +-------------------------------+

Cas Nécessitant une Session Persistante (Sticky)

  • **Montée en Température de Profils (Cookie Warming) :** Les profils de navigateurs ont besoin d'accumuler de l'historique et des cookies tiers. Les sessions actives doivent impérativement conserver la même IP d'origine sur plusieurs navigations successives pour bâtir une confiance télémétrique solide.
  • Sessions Authentifiées (OAuth, SSO, Espaces Clients) : Changer d'adresse IP au sein d'un tableau de bord applicatif ou bancaire conduit les moteurs de sécurité à révoquer les jetons de session, imposant des vérifications biométriques ou 2FA supplémentaires.
  • Tunnels d'Achat E-Commerce : De l'ajout au panier à la tokenisation de la carte bancaire via iframe (Stripe, Adyen), en passant par le calcul des frais d'expédition, l'empreinte IP et TLS doit être rigoureusement stable.
  • Collecte Interactrice Multi-Vues : Scraping d'écrans complexes utilisant des jetons éphémères à usage unique (single-use tokens) ou des états stockés localement au sein de l'environnement de rendu du navigateur.

Cas Nécessitant une Rotation Immédiate

  • Post-Finalisation de Commande : Dès que la page de confirmation de paiement (/checkout/thank-you) s'affiche et que l'identifiant de commande est sécurisé dans vos bases, la session est achevée. Une rotation immédiate isole le profil d'achat avant de traiter le compte suivant.
  • Changement de Contexte Utilisateur : Ne traitez jamais deux comptes clients distincts consécutivement sur la même adresse IP mobile sans cycle de renouvellement complet. La rotation matérielle garantit l'absence totale de corrélation croisée.
  • Rencontre d'un Blocage 403 / Défi Captcha Résistant : Si un seuil de requêtes strict est atteint lors d'une extraction publique, déclenchez une rotation matérielle avant toute nouvelle tentative.
  • Collecte Sans État à Large Échelle : Pour l'indexation massive de catalogues, sitemaps ou annuaires non authentifiés, une rotation après chaque cycle de traitement ou par lot de requêtes permet d'échapper aux modèles de détection volumétrique.

6. Implémentations en Production : Python et Go

Les exemples de code suivants illustrent la gestion de tunnels d'achat à état persistant couplée à un déclenchement déterministe de la rotation matérielle via l'API REST de Proxym.

Implémentation A : Python 3 avec Playwright & API REST Proxym

Ce script utilise Playwright pour assurer une navigation séquentielle multi-étapes sans rupture réseau, puis commande une rotation matérielle une fois la transaction validée.

#!/usr/bin/env python3
"""
Framework d'Automatisation Haute Disponibilité : Flux Navigateur Persistant et Rotation Matérielle
Dépendances : pip install playwright requests
"""

import os
import time
import logging
import requests
from typing import Dict, Any, Optional
from playwright.sync_api import sync_playwright, BrowserContext, Page, Error as PlaywrightError

# Configuration du système de journalisation
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] (%(threadName)s) %(message)s"
)
logger = logging.getLogger("ProxymPipeline")

class ProxymController:
    """Contrôleur d'orchestration pour le matériel industriel Teltonika via l'API Proxym."""
    
    BASE_URL = "https://proxym.io/api"

    def __init__(self, api_key: str, assignment_id: str):
        self.api_key = api_key
        self.assignment_id = assignment_id
        self.headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }

    def trigger_rotation(self) -> bool:
        """Envoie l'ordre de réinitialisation radio pour acquérir une nouvelle IP CGNAT."""
        url = f"{self.BASE_URL}/proxies/{self.assignment_id}/rotate"
        logger.info(f"Déclenchement de la rotation matérielle sur le modem : {self.assignment_id}")
        
        try:
            response = requests.post(url, headers=self.headers, timeout=30)
            if response.status_code in [200, 202]:
                data = response.json()
                logger.info(f"Ordre de rotation validé par l'équipementier : {data}")
                return self._wait_for_ip_propagation()
            else:
                logger.error(f"Échec de l'ordre de rotation : HTTP {response.status_code} - {response.text}")
                return False
        except requests.RequestException as e:
            logger.error(f"Erreur réseau lors de l'appel à l'API Proxym : {str(e)}")
            return False

    def _wait_for_ip_propagation(self, timeout_sec: int = 45) -> bool:
        """Interroge l'état du modem jusqu'au rétablissement complet du porteur 5G."""
        logger.info("Attente de la négociation du nouveau contexte PDP opérateur...")
        start_time = time.time()
        time.sleep(5)  # Délai incompressible de coupure radio physique
        
        while time.time() - start_time < timeout_sec:
            url = f"{self.BASE_URL}/proxies/{self.assignment_id}/status"
            try:
                res = requests.get(url, headers=self.headers, timeout=10)
                if res.status_code == 200:
                    status_data = res.json()
                    if status_data.get("status") == "ONLINE":
                        logger.info(f"Modem reconnecté. Nouvelle IP Publique : {status_data.get('current_ip')}")
                        return True
            except requests.RequestException:
                pass
            time.sleep(3)
            
        logger.error("Délai dépassé lors de la reconnexion au réseau cellulaire.")
        return False


class PersistentCheckoutWorker:
    """Exécute un processus d'achat complet sur une liaison réseau strictement persistante."""

    def __init__(self, proxy_server: str, proxy_auth: Dict[str, str], proxym_ctrl: ProxymController):
        self.proxy_server = proxy_server
        self.proxy_auth = proxy_auth
        self.proxym_ctrl = proxym_ctrl

    def run_checkout_flow(self, user_data: Dict[str, Any]) -> bool:
        with sync_playwright() as p:
            # Lancement de