Exécution de tâches planifiées en Python sous NixOS

Exécuter un script Python avec ses modules proprement

Automatiser un script Python avec Systemd et NixOS

On a souvent besoin de lancer un script Python en arrière-plan pour mettre à jour des données, synchroniser un catalogue ou nettoyer une base de données. Mais comment s’assurer que ce script tourne tout seul, proprement, et qu’on puisse savoir exactement ce qu’il a fait sans fouiller dans des fichiers .log oubliés ?

Cet article va passer rapidement en revue la méthode pour se passer de cron et exécuter un script Python avec ses modules sous NixOS.

Si Cron fait le travail, Systemd offre un contrôle bien plus fin. On peut gérer les dépendances (attendre que le réseau soit actif), limiter les ressources et, surtout, centraliser la gestion des erreurs.

Le piège des modules Python sous NixOS

C’est ici que j’ai rencontré mes plus grandes difficultés.

Sous NixOS, appeler python3 ne suffit pas. Pourquoi ? Parce que Nix prône l’isolation. Le Python installé par défaut est « nu ». Si votre script utilise requests ou pandas, il plantera avec une erreur ModuleNotFoundError.

La solution consiste à créer un environnement Python spécifique. Dans notre configuration, on utilise python3.withPackages. On définit ainsi un binaire Python qui contient exactement les bibliothèques dont le script a besoin, et rien d’autre. C’est propre, reproductible et cela évite les conflits de versions.

Les logs : adieu les fichiers .log, bonjour Journalctl

L’habitude est de rediriger la sortie d’un script vers un fichier texte. C’est fastidieux à lire, cela finit par remplir le disque ou demande de configurer logrotate.

En configurant un service Systemd, on laisse le système gérer les logs. En supprimant les redirections de sortie, tout ce que Python affiche (via print ou les erreurs de crash) est directement envoyé vers journalctl.

L’avantage ? On peut filtrer les logs par date, par priorité ou par service en une seule commande :

1
journalctl -u update-data -f

(pour suivre les logs en temps réel)

Résumé pour mettre en place votre tâche périodique

  1. Le Service : On définit ce qui doit être exécuté, avec un Python équipé de ses modules.
  2. Le Timer : On définit quand l’exécuter (toutes les heures, tous les jours à 3 h du matin, etc.).
  3. Le Journal : On laisse Systemd capturer les flux pour garder un historique propre et accessible.

C’est simple, robuste et maintenable.

Exemple de configuration NixOS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
let
  pythonWithDeps = pkgs.python3.withPackages (
    ps: with ps; [
      requests
      beautifulsoup4
      flask
    ]
  );
  sitePath = "/srv/www/domain.fr";
  domain = "domain.fr";
  adminEmail = "adress@domain.fr";
in
{
  # ...

  systemd.services.update-data = {
    description = "Update site data";

    serviceConfig = {
      Type = "oneshot";
      User = "caddy";
      WorkingDirectory = sitePath;
      # Autorise l'écriture spécifiquement dans ce chemin
      ReadWritePaths = [ "${sitePath}/data" ];
      # Optionnel : s'assure que le reste du système est protégé mais pas
      # ce dossier
      ProtectSystem = "full";
    };

    script = ''
      echo "Début de la mise à jour des données"
      ${pythonWithDeps}/bin/python3 ${sitePath}/update_data.py

      rc=$?
      if [ $rc -eq 0 ]; then
        echo "Mise à jour terminée avec succès"
      else
        echo "Erreur lors de la mise à jour (code=$rc)"
      fi
      exit $rc
    '';
  };

  # ...
}
Généré avec Hugo
Thème Stack conçu par Jimmy