sdk_relay/IMPROVEMENTS.md

5.4 KiB

Améliorations de la séquence de démarrage de sdk_relay

Problème actuel

  • Le serveur WebSocket ne démarre qu'après le scan complet des blocs
  • Les services dépendants (ihm_client, etc.) ne peuvent pas se connecter pendant le scan
  • Le scan peut prendre plusieurs minutes et bloquer complètement le service

Solutions proposées

1. Démarrage immédiat des serveurs (Recommandé)

// Dans main.rs, démarrer les serveurs AVANT le scan
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ... configuration ...

    // DÉMARRER LES SERVEURS IMMÉDIATEMENT
    let try_socket = TcpListener::bind(config.ws_url).await?;
    let listener = try_socket;

    // Démarrer le serveur de santé immédiatement
    tokio::spawn(start_health_server(8091));

    // Démarrer le serveur WebSocket dans une tâche séparée
    let ws_handle = tokio::spawn(async move {
        while let Ok((stream, addr)) = listener.accept().await {
            tokio::spawn(handle_connection(stream, addr, our_sp_address));
        }
    });

    // FAIRE LE SCAN EN ARRIÈRE-PLAN
    tokio::spawn(async move {
        if let Err(e) = scan_blocks(current_tip - last_scan, &config.blindbit_url).await {
            eprintln!("Scan error: {}", e);
        }
    });

    // Attendre que le serveur WebSocket soit prêt
    ws_handle.await?;
    Ok(())
}

2. Mode "dégradé" pendant le scan

// Ajouter un état de service
enum ServiceState {
    Starting,
    Scanning,
    Ready,
    Error,
}

// Le serveur WebSocket accepte les connexions mais répond avec un état
async fn handle_connection(stream: TcpStream, addr: SocketAddr, state: Arc<Mutex<ServiceState>>) {
    let current_state = state.lock().await;
    match *current_state {
        ServiceState::Scanning => {
            // Répondre avec un message indiquant que le service est en cours de scan
            send_message(stream, json!({
                "status": "scanning",
                "message": "Service is scanning blocks, please wait..."
            })).await;
        },
        ServiceState::Ready => {
            // Traitement normal des messages
            handle_normal_connection(stream).await;
        },
        _ => {
            // Répondre avec une erreur
            send_error(stream, "Service not ready").await;
        }
    }
}

3. Scan incrémental en arrière-plan

// Modifier le scan pour qu'il soit non-bloquant
async fn start_background_scan(start_block: u32, end_block: u32, blindbit_url: &str) {
    let mut current = start_block;
    while current <= end_block {
        match scan_single_block(current, blindbit_url).await {
            Ok(_) => {
                current += 1;
                // Mettre à jour le last_scan dans le wallet
                update_last_scan(current).await;
            },
            Err(e) => {
                eprintln!("Error scanning block {}: {}", current, e);
                // Attendre un peu avant de réessayer
                tokio::time::sleep(Duration::from_secs(5)).await;
            }
        }
    }
}

4. Healthcheck amélioré

async fn start_health_server(port: u16) {
    let listener = TcpListener::bind(format!("0.0.0.0:{}", port)).await.unwrap();

    while let Ok((stream, _)) = listener.accept().await {
        tokio::spawn(async move {
            let response = match get_service_state().await {
                ServiceState::Ready => json!({"status": "ok", "scan_complete": true}),
                ServiceState::Scanning => json!({"status": "ok", "scan_complete": false, "message": "Scanning in progress"}),
                ServiceState::Starting => json!({"status": "starting", "scan_complete": false}),
                ServiceState::Error => json!({"status": "error", "scan_complete": false}),
            };

            let response_str = response.to_string();
            let http_response = format!(
                "HTTP/1.1 200 OK\r\nContent-Length: {}\r\nContent-Type: application/json\r\n\r\n{}",
                response_str.len(),
                response_str
            );

            let _ = stream.write_all(http_response.as_bytes()).await;
        });
    }
}

Implémentation recommandée

Étape 1 : Modifier main.rs

  1. Démarrer les serveurs WebSocket et de santé immédiatement
  2. Faire le scan en arrière-plan dans une tâche séparée
  3. Ajouter un état de service partagé

Étape 2 : Modifier le healthcheck

  1. Retourner l'état du scan dans la réponse
  2. Permettre aux services de savoir si le scan est terminé

Étape 3 : Modifier docker-compose.yml

sdk_relay:
  # ... configuration existante ...
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:8091/"]
    interval: 10s
    timeout: 5s
    retries: 3
    start_period: 30s  # Donner plus de temps pour le démarrage initial

Étape 4 : Modifier les services dépendants

ihm_client:
  depends_on:
    sdk_relay:
      condition: service_healthy
  # Ajouter une vérification de l'état du scan
  environment:
    - SDK_RELAY_SCAN_TIMEOUT=300  # 5 minutes max d'attente

Avantages

  • Services disponibles immédiatement
  • Scan non-bloquant
  • Meilleure expérience utilisateur
  • Monitoring de l'état du scan
  • Récupération d'erreur améliorée

Migration

  1. Implémenter les changements dans sdk_relay
  2. Tester avec un scan réduit
  3. Déployer en production
  4. Surveiller les logs et métriques