rsky-pds-crawler-notify-hang

Par divinevideo · divine-mobile

Corrige le blocage indéfini de createRecord/putRecord dans rsky-pds, sans aucun log d'erreur. À utiliser quand : (1) createSession réussit mais createRecord ne retourne jamais, (2) Aucune erreur n'apparaît dans les logs du PDS malgré une requête bloquée depuis 60+ secondes, (3) L'endpoint de santé du PDS fonctionne mais les opérations d'écriture sont bloquées, (4) Les readiness probes échouent de façon intermittente sur le pod rsky-pds. Cause racine : la variable d'environnement PDS_CRAWLERS configure des URLs de notification de crawler appelées via le client HTTP reqwest SANS aucun timeout dans crawlers.rs. Si l'URL du crawler est inaccessible depuis le cluster, chaque écriture se bloque indéfiniment. À noter : définir PDS_CRAWLERS="" produit [""] (un élément chaîne vide) ce qui provoque une "builder error" à la place — la variable d'environnement doit être entièrement désactivée.

npx skills add https://github.com/divinevideo/divine-mobile --skill rsky-pds-crawler-notify-hang

Blocage de notification du Crawler rsky-pds

Problème

Toutes les opérations d'écriture sur rsky-pds (createRecord, putRecord, deleteRecord) se bloquent indéfiniment sans erreur. Le PDS semble sain (l'endpoint health retourne 200, createSession fonctionne) mais aucune opération modifiant le repo ne se termine.

Contexte / Conditions de déclenchement

  • createSession retourne un JWT valide instantanément
  • createRecord ou putRecord avec ce JWT se bloque indéfiniment (timeout 60s+)
  • Les logs du PDS affichent uniquement Rocket has launched from http://0.0.0.0:8000 sans erreur
  • L'endpoint _health retourne {"version":"0.3.0-beta.3"} (ou similaire)
  • Les probes de readiness Kubernetes peuvent échouer par intermittence car le pod est submergé par les requêtes bloquées
  • La variable d'env PDS_CRAWLERS est définie (ex. https://bsky.network)

Solution

Correctif rapide (Runtime)

Désactiver entièrement la variable d'env PDS_CRAWLERS :

# IMPORTANT : Utiliser le tiret final pour DÉSACTIVER, ne pas définir à une chaîne vide
kubectl set env deployment/rsky-pds -n <namespace> PDS_CRAWLERS-

# Attendre le déploiement
kubectl rollout status deployment/rsky-pds -n <namespace> --timeout=120s

NE PAS définir PDS_CRAWLERS="" — le parseur env_list() divise sur les virgules, donc une chaîne vide produit vec![""] (un élément chaîne vide), ce qui cause une "builder error" quand reqwest essaie de construire une URL à partir de "".

Correctif de code (Permanent)

Dans rsky-pds/src/crawlers.rs, ajouter un timeout au client reqwest :

let client = reqwest::Client::builder()
    .user_agent(APP_USER_AGENT)
    .timeout(std::time::Duration::from_secs(5))  // Ajouter ceci
    .connect_timeout(std::time::Duration::from_secs(3))  // Ajouter ceci
    .build()?;

Envisager aussi de rendre l'erreur non-fatale (utiliser let _ = pour ignorer les échecs au lieu de propager avec ?), puisque la notification du crawler n'est pas critique pour le succès de l'opération d'écriture.

Analyse de la cause racine

Le chemin d'écriture dans rsky-pds est :

  1. createRecord -> process_writes -> format_commit (DB, fonctionne bien)
  2. sequence_commit -> sequence_evt -> crawlers.notify_of_update() (SE BLOQUE)

notify_of_update() dans crawlers.rs crée un reqwest::Client sans timeout configuré et POST à chaque URL de crawler. Depuis un cluster GKE, la requête vers https://bsky.network/xrpc/com.atproto.sync.requestCrawl peut se bloquer au niveau TCP sans réponse, causant l'arrêt de l'ensemble de l'opération d'écriture.

Fichiers clés :

  • rsky-pds/src/crawlers.rs:30-61 — méthode notify_of_update()
  • rsky-pds/src/sequencer/mod.rs:215 — appelle crawlers.notify_of_update()
  • rsky-pds/src/apis/com/atproto/repo/create_record.rs:100 — acquiert le verrou du sequencer
  • rsky-common/src/env.rs:28-33 — parseur env_list() qui divise les chaînes vides

Vérification

Après désactivation de PDS_CRAWLERS :

# Devrait retourner en <10 secondes au lieu de se bloquer
curl -X POST "$PDS_URL/xrpc/com.atproto.repo.createRecord" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{"repo":"$DID","collection":"app.bsky.feed.post","record":{"$type":"app.bsky.feed.post","text":"test","createdAt":"2026-01-01T00:00:00Z"}}'

Notes

  • Cela affecte TOUS les déploiements de rsky-pds qui définissent PDS_CRAWLERS à une URL inatteignable
  • Le PDS atproto TypeScript en amont a des timeouts appropriés ; c'est un bug spécifique à rsky
  • notify_of_update() a un throttle de 20 minutes, donc la première écriture après le démarrage déclenche toujours la notification (et se bloque si inatteignable)
  • Le verrou d'écriture du sequencer à la ligne 99 signifie qu'une seule notification bloquée bloque TOUTES les requêtes d'écriture suivantes, pas seulement celle qui l'a déclenchée

Skills similaires