> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

> Découvrez comment W&B Sweeps gère les signaux UNIX, les codes de sortie et la préemption dans les runs de sweep.

# Gestion des signaux et runs de sweep

Cette page explique en détail comment W\&B Sweeps gère les signaux système et les codes de sortie des processus. Utilisez ces informations pour exécuter des sweeps de manière fiable dans des environnements préemptibles tels que SLURM, EC2 Spot ou les VM préemptibles de Google Cloud. Les sections suivantes décrivent comment interrompre proprement des runs depuis le clavier et apportent des précisions pour vous aider à comprendre et à anticiper la façon dont les runs sont remis en file d’attente. Cette page s’adresse aux utilisateurs qui exécutent des sweeps sur une infrastructure préemptible ou qui ont besoin d’un contrôle précis sur le cycle de vie et le nettoyage des runs. Pour en savoir plus sur la façon dont W\&B remet les runs en file d’attente lorsqu’ils sont préemptés, consultez [Reprendre les runs de sweep préemptibles](/fr/products/wandb/runs/resuming#resume-preemptible-sweeps-runs).

<h2 id="exit-status-and-signals">
  Statut de sortie et signaux
</h2>

W\&B utilise le statut de sortie du processus d’entraînement pour déterminer si un run est remis en file d’attente et comment son état est enregistré.

**Contrat des codes de sortie :**

* **Code de sortie 0** : W\&B considère que le run s’est terminé avec succès et ne le remet pas en file d’attente.
* **Code de sortie non nul** : W\&B considère que le run a échoué ou a été préempté. Lorsque vous utilisez [`mark_preempting()`](/fr/products/wandb/ref/python/experiments/run#mark_preempting), W\&B remet le run en file d’attente afin qu’un autre agent (ou le même agent après redémarrage) puisse le reprendre.

Ce comportement s’applique que le processus se termine depuis un gestionnaire de signal, à la suite d’une exception ou par un appel explicite à `sys.exit()`. Dans les environnements préemptibles ou en cluster, il est essentiel de bien comprendre ce contrat et de s’appuyer dessus.

Lorsque le processus se termine en raison d’un [signal interceptable](#catchable-signals-and-preemption), votre gestionnaire peut s’exécuter, appeler [`wandb.run.mark_preempting()`](/fr/products/wandb/ref/python/experiments/run#mark_preempting) si vous souhaitez que le run soit remis en file d’attente, effectuer un nettoyage (par exemple, enregistrer un point de contrôle), puis se terminer avec un code non nul. Par convention, on utilise généralement `sys.exit(128 + signum)` pour une terminaison par signal. W\&B enregistre ce code de sortie, et les mêmes [règles de remise en file d’attente](/fr/products/wandb/runs/resuming#resume-preemptible-sweeps-runs) s’appliquent. Lorsque le noyau du système d’exploitation tue le processus avec [`SIGKILL`](#sigkill-uncatchable), le processus ne peut pas exécuter les hooks de sortie : W\&B n’écrit donc pas de synthèse finale, et le run peut apparaître comme planté ou tué. L’agent démarre néanmoins le run suivant.

<h2 id="stale-runs-and-server-side-timeouts">
  Runs inactifs et délais d’expiration côté serveur
</h2>

W\&B détermine l’état d’un run à partir des codes de sortie, mais aussi de l’activité du run. Si un run ne se termine pas et ne publie aucune nouvelle métrique pendant environ 5 minutes, W\&B le marque comme planté. Cela peut se produire lorsque le processus d’entraînement ne répond plus, cesse de journaliser ou s’arrête sans sortie propre (par exemple, après l’envoi d’un `SIGKILL`). Consignez des métriques à intervalles réguliers ou terminez le processus avec un code de sortie défini, afin que l’état du run reflète fidèlement ce qui s’est réellement produit.

<h2 id="catchable-signals-and-preemption">
  Signaux interceptables et préemption
</h2>

Dans les environnements préemptibles, la plupart des signaux sont interceptables : votre script d’entraînement peut donc les intercepter et s’arrêter proprement. Vous pouvez enregistrer des gestionnaires de signaux personnalisés dans votre script d’entraînement. Lorsque le système envoie un signal interceptable, votre gestionnaire s’exécute. W\&B conserve les métriques qu’il a déjà reçues. L’agent détecte la fin du processus et lance le run suivant.

**Bonnes pratiques :**

* Enregistrez les gestionnaires le plus tôt possible (par exemple, avant d’entrer dans la boucle d’entraînement principale).
* Dans le gestionnaire, appelez [`wandb.run.mark_preempting()`](/fr/products/wandb/ref/python/experiments/run#mark_preempting) si vous souhaitez que le run soit remis en file d’attente après la préemption, effectuez le nettoyage (par exemple, enregistrez un point de contrôle), puis quittez avec un code de sortie non nul.

L’exemple suivant enregistre des gestionnaires pour `SIGUSR1` (un signal de préemption courant sur les clusters) et `SIGTERM`. Il laisse `SIGINT` disponible pour une utilisation interactive (par exemple, une annulation manuelle depuis le terminal). Le gestionnaire appelle `wandb.run.mark_preempting()` et quitte avec le code `128 + signum` :

```python theme={"system"}
import signal
import sys
import wandb


def signal_handler(signum, frame):
    if wandb.run is not None:
        # Facultatif : enregistrer un point de contrôle du modèle, vider les tampons, etc.
        print(f"Preempted with signal: {signal.Signals(signum).name}.")
        wandb.run.mark_preempting()
    sys.exit(128 + signum)


def train():
    signal.signal(signal.SIGUSR1, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    with wandb.init() as run:
        config = wandb.config
        for epoch in range(100):
            # Étape d'entraînement ; appeler wandb.log(...) si nécessaire
            pass


if __name__ == "__main__":
    train()
```

<h2 id="sigkill-uncatchable">
  `SIGKILL` (non interceptable)
</h2>

`SIGKILL` provient du noyau du système d’exploitation et ne peut être ni intercepté ni ignoré. Le processus s’arrête immédiatement, sans pouvoir exécuter de gestionnaires ni de callbacks `atexit`. W\&B ne peut pas écrire la synthèse finale du run. L’agent parvient malgré tout à se rétablir et poursuit le sweep, mais les données de ce run restent incomplètes. N’utilisez `SIGKILL` qu’en dernier recours. Si vous avez besoin d’un arrêt propre, privilégiez `SIGTERM` ou `SIGINT`.

<h2 id="signal-forwarding-from-agent-to-child">
  Transfert des signaux de l’agent vers le processus enfant
</h2>

Lorsque vous utilisez la CLI [`wandb agent`](/fr/products/wandb/ref/cli/wandb-agent), l’agent exécute votre script d’entraînement en tant que processus enfant. Lorsque vous interrompez l’agent (par exemple avec Ctrl+C, ou lorsqu’un scheduler envoie `SIGTERM` au job), le processus enfant (le processus d’entraînement) ne reçoit pas le signal par défaut. Le script d’entraînement ne peut alors ni exécuter son gestionnaire ni appeler `mark_preempting()`. Pour plus d'informations, voir [le ticket GitHub wandb n° 3667](https://github.com/wandb/wandb/issues/3667).

Pour permettre au processus enfant de s’arrêter proprement et d’appeler `wandb.run.mark_preempting()` dans un gestionnaire, exécutez l’agent CLI avec l’option `--forward-signals` :

```bash theme={"system"}
wandb agent --forward-signals entity/project/sweep_ID
```

W\&B ne prend pas en charge le transfert de signaux pour [`wandb.agent()`](/fr/products/wandb/ref/python/functions/agent) dans l'API Python. Dans ce cas, votre fonction d'entraînement s'exécute dans un thread et non dans un processus enfant distinct : le transfert ne fonctionne donc pas de la même manière.

Lorsque l'agent CLI reçoit `SIGINT` ou `SIGTERM` alors que le transfert est activé, il relaie le signal au processus enfant. Le gestionnaire de votre script d'entraînement peut alors s'exécuter, appeler `wandb.run.mark_preempting()` et, si nécessaire, [`wandb.finish()`](/fr/products/wandb/ref/python/experiments/run#finish) avec un code de sortie non nul, puis se terminer avec un code non nul. Si vous appuyez deux fois sur Ctrl+C dans le processus de l'agent, celui-ci reçoit `SIGTERM` par défaut. Avec `--forward-signals`, l'agent peut transférer `SIGINT` au processus enfant afin que votre gestionnaire s'exécute.

Pour plus d'informations, consultez la référence CLI de [`wandb agent`](/fr/products/wandb/ref/cli/wandb-agent).

<h2 id="preemptible-clusters-like-slurm">
  Clusters préemptibles comme SLURM
</h2>

Cette section explique comment configurer les sweeps pour que les runs survivent à la préemption sur des clusters tels que SLURM, EC2 Spot ou les VM préemptibles de Google Cloud. En cas de préemption, le processus d’entraînement doit recevoir le signal, marquer le run comme en cours de préemption, puis se terminer avec un code non nul pour que W\&B remette le run en file d’attente. Un nouvel agent (ou le même agent, une fois le job remis en file d’attente) peut alors reprendre le run.

**Assurez-vous que le processus d’entraînement reçoit le signal :**

* **Lorsque le scheduler envoie le signal à l’agent** : exécutez l’agent avec `wandb agent --forward-signals` pour que, lorsque le scheduler (ou l’utilisateur) envoie un signal à l’agent, celui-ci le transmette au processus enfant. Le gestionnaire du processus enfant peut alors appeler `wandb.run.mark_preempting()`, [`wandb.finish(exit_code=...)`](/fr/products/wandb/ref/python/experiments/run#finish) avec un code non nul, puis `sys.exit(128 + signum)` (ou un autre code de sortie non nul).
* **Lorsque le scheduler envoie le signal au script de lancement (et non directement à l’agent)** : faites en sorte que le script de lancement transmette le signal de préemption directement au processus d’entraînement. Par exemple, le script d’entraînement écrit son identifiant de processus (PID) dans un fichier. Le script de lancement intercepte le signal du cluster (par exemple, `SIGUSR1`) et exécute `kill -SIGUSR1 $(cat $PID_FILE)` pour déclencher le gestionnaire du processus d’entraînement.

**Dans le script d’entraînement :** enregistrez un gestionnaire pour le signal utilisé par votre cluster (par exemple, `SIGTERM` ou `SIGUSR1`). Dans ce gestionnaire, appelez `wandb.run.mark_preempting()` si un run est actif, puis terminez le run avec un code de sortie non nul et appelez `sys.exit(128 + signum)` (ou un autre code non nul) pour que W\&B remette le run en file d’attente. Pour savoir dans quels cas W\&B remet les runs en file d’attente et comment cela interagit avec `mark_preempting()`, voir [Reprendre les runs Sweeps préemptibles](/fr/products/wandb/runs/resuming#resume-preemptible-sweeps-runs).

**État du sweep :** exécutez `wandb sweep entity/project/sweep_ID --resume` avant de démarrer l’agent, afin que le sweep passe en mode reprise et distribue les runs remis en file d’attente.

**Coordination multi-agents :** lorsque de nombreux agents s’exécutent simultanément (par exemple avec des array jobs SLURM), ils peuvent se disputer le même run préempté. Il s’agit d’une limitation connue. Pour la contourner, échelonnez le démarrage des agents ou utilisez des mécanismes de coordination externes, tels que des verrous.

Pour les jobs SLURM multi-GPU dans lesquels un seul processus doit appeler `wandb.agent()`, voir [Comment exécuter des sweeps sur SLURM ?](/fr/support/models/articles/how-should-i-run-sweeps-on-slurm).

<h2 id="wandb-sweep-cancel">
  `wandb sweep --cancel`
</h2>

Cette section décrit comment la commande `--cancel` interagit avec les signaux et les processus enfants, car l’annulation ne se comporte pas de la même manière que l’envoi direct d’un signal du système d’exploitation. L’annulation d’un sweep passe par l’API W\&B, et non par un signal du système d’exploitation. Exécutez une commande telle que `wandb sweep --cancel entity/project/sweep_ID`. Le serveur demande à l’agent de s’arrêter ; l’agent met alors fin aux processus enfants en cours d’exécution, puis s’arrête. Un court délai (de l’ordre de l’intervalle d’interrogation de l’API par l’agent) peut s’écouler avant que l’annulation ne prenne effet.

L’annulation envoie `SIGKILL` aux runs. Les processus enfants n’ont donc pas la possibilité d’exécuter les gestionnaires de signaux définis par l’utilisateur. Il en va de même lorsque vous utilisez la commande **Cancel** dans l’interface Sweeps. Utilisez `--cancel` lorsque vous souhaitez arrêter l’ensemble du sweep et le marquer comme annulé. Pour arrêter proprement le run actuel, envoyez-lui un signal interceptable (ou utilisez `--forward-signals` avec l’agent CLI et envoyez le signal à l’agent). Pour terminer proprement un sweep, utilisez [`wandb sweep --stop`](/fr/products/wandb/sweeps/pause-resume-and-cancel-sweeps#stop-a-sweep) plutôt que `--cancel`.

Pour plus d’informations sur les options de mise en pause, de reprise, d’arrêt et d’annulation, voir [Gérer les sweeps](/fr/products/wandb/sweeps/pause-resume-and-cancel-sweeps).

<h2 id="signals-to-the-agent-versus-signals-to-the-run">
  Signaux envoyés à l’agent ou signaux envoyés au run
</h2>

Faire la distinction entre l’envoi d’un signal à l’agent et l’envoi d’un signal au run d’entraînement vous permet d’éviter les processus orphelins et les comportements inattendus. Si vous envoyez un signal au processus de l’agent (et non au processus d’entraînement enfant), l’agent peut s’arrêter alors que le processus enfant continue de s’exécuter en tant qu’orphelin. Ce processus orphelin peut continuer à écrire dans votre terminal, et le shell peut ne pas afficher de nouvelle invite tant que vous n’appuyez pas sur Entrée.

Si vous n’utilisez pas `--forward-signals` avec l’agent CLI, l’arrêt de l’agent ne garantit pas celui du processus d’entraînement enfant.

Pour vérifier que l’agent s’est bien arrêté, utilisez une commande du système d’exploitation comme `ps -p [AGENT-PID]` ou `pgrep -f "wandb agent"` plutôt que de vous fier à l’apparition de l’invite.

<h2 id="reference-mark_preempting-and-final-run-state">
  Référence : `mark_preempting()` et état final du run
</h2>

Le tableau suivant résume comment l’état du run varie selon le moment où vous appelez `mark_preempting()` et la façon dont le processus se termine. Il part du principe que vous utilisez la CLI [`wandb agent`](/fr/products/wandb/ref/cli/wandb-agent) et que votre programme d’entraînement s’exécute comme sous-processus.

| Scénario | Sans `mark_preempting()` | Le gestionnaire de signal appelle `mark_preempting()` et se termine avec un code non nul | `mark_preempting()` toujours appelé juste après `init()` |
| - | - | - | - |
| Le run se termine normalement avec le code de sortie 0 | FINISHED | FINISHED | FINISHED |
| Le run échoue avec un code de sortie non nul | FAILED | FAILED | PREEMPTED |
| Le run reçoit `SIGKILL` | CRASHED après environ 5 minutes | CRASHED après environ 5 minutes (non interceptable) | PREEMPTED après environ 5 minutes |
| Le run reçoit `SIGINT` | KILLED | PREEMPTED (avec un gestionnaire `SIGINT`) | PREEMPTED |
| Le run reçoit un autre signal (par exemple, `SIGTERM` ou `SIGUSR1`) | CRASHED après environ 5 minutes | PREEMPTED (avec un gestionnaire correspondant) | PREEMPTED après environ 5 minutes |

Si vous appelez `mark_preempting()` uniquement dans un gestionnaire de signal, vous ne couvrez pas les cas où le gestionnaire ne s’exécute jamais, comme avec `SIGKILL`.

Si vous appelez systématiquement `mark_preempting()` immédiatement après `wandb.init()`, W\&B peut traiter tout échec comme une préemption et risque de remettre le run en file d’attente à répétition, y compris en cas de bogue ou de configuration incorrecte.

Dans les environnements disposant d’un signal de préemption bien défini, l’approche habituelle consiste à utiliser un gestionnaire de signal qui appelle `mark_preempting()` et se termine avec un code non nul, plutôt qu’un appel inconditionnel après `init()`.
