De la scrutation à l’interruption — repenser l’architecture d’un assistant personnel

Rédaction assistée par IA Rédaction assistée par IA

De la scrutation à l’interruption — repenser l’architecture d’un assistant personnel

Le problème du polling

Quand on construit un assistant personnel auto-hébergé, la tentation naturelle est de scruter : un cron qui vérifie toutes les X minutes si quelque chose a changé. C’est simple, c’est fiable, ça marche.

Mais ça a un coût.

Prenons un exemple concret. Mon assistant (Hermes Agent) devait vérifier :

  • La boîte de réception : des fichiers déposés dans un dossier — toutes les 3 heures
  • L’état de sécurité : les IP bannies par fail2ban — toutes les 5 minutes
  • Les emails : via IMAP — toutes les 10 minutes
  • Les bookmarks (Karakeep) — toutes les 60 minutes
  • Le dashboard — toutes les 30 minutes

Chaque scrutation, c’est un appel système, un script qui s’exécute, des tokens LLM consommés pour rien la plupart du temps. Le pire, c’est le SOC (Security Operations Center) : 288 vérifications par jour pour, dans 99% des cas, ne rien trouver. Et quand quelque chose arrive, on le découvre en moyenne 2 minutes 30 après les faits.

Il y a mieux à faire.

Le paradigme de l’interruption

Dans un système d’exploitation, on n’a pas inventé les interruptions pour rien. Attendre qu’un périphérique termine en bouclant sur un registre d’état, c’est du polling. Recevoir un signal électrique qui dit « j’ai fini », c’est une interruption. La différence, c’est la latence, la charge CPU, et l’élégance.

J’ai appliqué la même logique à mon assistant.

1. inotify — la boîte de réception en temps réel

Linux expose inotify depuis des années : une API du noyau qui permet de surveiller des fichiers et d’être notifié immédiatement à la moindre création, modification ou suppression.

J’ai écrit un petit daemon (50 lignes de bash) qui :

1. Surveille le dossier de la boîte de réception avec inotifywait
2. Dès qu’un fichier apparaît, construit un payload JSON
3. Le POSTe sur un webhook local (Hermes écoute sur un port dédié)

Avant : cron toutes les 3 heures → latence moyenne 90 minutes
Après : inotify → latence < 1 seconde

Le cron a été supprimé. Zéro appel inutile. Zéro token gaspillé.

2. fail2ban action — la sécurité en push

fail2ban est un excellent outil, mais par défaut il se contente de bannir des IP dans nftables. Pour être informé, il fallait soit scruter les logs, soit scruter l’état des jails.

Sauf que fail2ban supporte nativement les actions : des scripts ou commandes exécutés automatiquement à chaque ban ou unban.

J’ai créé une action hermes-webhook qui, à chaque ban :

1. Construit un payload JSON (jail, IP, nombre de bans, timestamp)
2. Le signe avec HMAC-SHA256 (authentification)
3. Le POSTe sur le même webhook Hermes

Avant : cron toutes les 5 minutes → latence moyenne 2 min 30, 288 exécutions/jour
Après : action fail2ban → latence < 1 seconde, 0 exécution superflue

Le cron SOC a été réduit de 5 à 30 minutes (gardé uniquement pour les métriques système : charge, disque, mémoire — qui, elles, n’ont pas d’événement déclencheur).

3. L’architecture webhook

Le cœur du système, c’est un webhook Hermes — un petit serveur HTTP qui écoute sur localhost et achemine les payloads vers des abonnements configurés.

« 
Événement (fichier créé, IP bannie)


Agent déclencheur (inotify, fail2ban)


POST HTTP → localhost:8644/webhooks/


Hermes reçoit, traite, agit
`

Chaque abonnement a :

  • Une route (ex: inbox-new, soc-alert`)
  • Un secret partagé pour signer les payloads
  • Un prompt qui décrit comment traiter l’événement

L’avantage ? C’est générique. N’importe quel service capable de faire un POST HTTP peut notifier Hermes. Pas de SDK, pas de bibliothèque, pas de protocole exotique.

Bilan

| Service | Avant (polling) | Après (interrupt) | Gain |

Boîte réception Cron 180 min inotify → webhook 90 min → < 1s
SOC (bans) Cron 5 min fail2ban action → webhook 2.5 min → < 1s
SOC (système) Cron 5 min Cron 30 min 6× moins
Emails IMAP polling à faire

Ce qui a été supprimé : 2 jobs cron, ~300 exécutions quotidiennes inutiles, des tokens LLM gaspillés à constater qu’il ne s’était rien passé.

Ce qui a été ajouté : 1 daemon systemd (inotify), 1 action fail2ban, 2 abonnements webhook. Le tout tient dans ~80 lignes de code.

Leçons

1. Le polling est un défaut de conception, pas une fatalité. Avant d’ajouter un cron, demandez-vous : « est-ce que cet événement peut être poussé plutôt que scruté ? »

2. Les outils qu’on utilise ont souvent des mécanismes d’interruption qu’on ignore. inotify est dans le noyau Linux depuis 2005. fail2ban supporte les actions depuis toujours. Le webhook est un pattern HTTP vieux de 20 ans. Le problème n’est pas technique, c’est qu’on n’y pense pas.

3. Moins de code, moins de maintenance. Le cron SOC faisait 75 lignes de bash. L’action fail2ban fait 23 lignes. Le daemon inotify fait 50 lignes. Et ils ne tournent que quand il se passe quelque chose.

4. L’architecture événementielle n’est pas réservée aux gros systèmes. Un VPS à 5€/mois peut très bien faire de l’event-driven. C’est une question de design, pas de budget.

Et après ?

La prochaine cible, c’est IMAP IDLE — le mécanisme qui permet à un client email de rester connecté et de recevoir les nouveaux messages en temps réel, sans polling. Mais ça, ce sera pour un prochain article.

En attendant, tout le code et la documentation sont disponibles sur GitHub :

👉 github.com/rouzejp/hermes-assistant-etendu

Le dépôt est jeune, il s’enrichira au fil des articles. L’idée est d’en faire un point d’entrée unique pour quiconque voudrait construire un assistant personnel similaire — pas un copier-coller, mais une source d’inspiration et de patterns reproductibles.

† 3 revisions

Laisser un commentaire

To respond on your own website, enter the URL of your response which should contain a link to this post's permalink URL. Your response will then appear (possibly after moderation) on this page. Want to update or remove your response? Update or delete your post and re-enter your post's URL again. (Find out more about Webmentions.)