Version : 4.15.0 Société : AISIA — Structure juridique en cours de création URL publique : https://aisia.fr/
---
1. Architecture de maintenance centralisée 2. Catalogue des 17 tâches 3. Scheduler automatisé 4. Backup MariaDB et Qdrant 5. Backup Redis 6. Backup off-site 7. Purge Docker 8. Hot-reload des modèles locaux 9. Procédures de recovery 10. Audit et conformité 11. Coordination multi-replicas 12. Monitoring de la maintenance
---
AISIA remplace les anciens cron jobs distribués sur les workers du cluster par un système de maintenance centralisé, pilotable via l'API d'administration.
deploy/cluster-maintenance/| Aspect | Anciens cron | Maintenance centralisée |
|---|---|---|
| Visibilité | Dispersée sur 21 noeuds | Console unique |
| Exécution | Pas de coordination | Leader election + sémaphore |
| Historique | Logs syslog épars | Rapport JSON structuré |
| Contrôle | Modification SSH | API REST + interface web |
| Monitoring | Manuel | Prometheus + Redis |
Le catalogue est défini dans maintenance_tasks.yaml à la racine du projet.
Chaque tâche possède les attributs suivants :
| Attribut | Type | Description |
|---|---|---|
task_id | string | Identifiant unique |
title | string | Nom court |
description | string | Description détaillée |
category | string | Catégorie (cluster/audit/backup/maintenance/rgpd/integrations/analysis) |
command | list | Commande à exécuter |
cwd | string | Répertoire de travail |
enabled | bool | Tâche active |
auto_run | bool | Exécution automatique |
interval_s | int | Intervalle entre exécutions (secondes) |
timeout_s | int | Timeout d'exécution |
tags | list | Tags pour filtrage |
replaces_cron | list | Crons remplacés |
destructive | bool | Indique une opération potentiellement destructrice |
#### Cluster (2 tâches)
cluster-runtime-reconcile (auto, 15min)
Réconcilie le runtime Docker sur les workers.
Vérifie que /var/lib/docker reste monté sur le SAN et que Docker reste actif.
Remplace : @reboot (sleep 10;/bin/mount -a;systemctl restart docker)
/10 * docker mount sanity + restart
cluster-docker-prune (manuel, destructif)
Purge Docker sur les workers : docker system prune --all --volumes --force.
Tâche manuelle par sécurité car elle peut supprimer des artefacts utiles.
Remplace : 30 0 * docker system prune --all --volumes --force
#### Audit (6 tâches)
cluster-root-usage-audit (auto, 1h)
Contrôle de l'occupation disque locale des workers.
cluster-logging-audit (auto, 30min)
Vérifie que les workers envoient leurs logs au collecteur syslog du manager.
Remplace : /etc/cron.d/sysstat
manager-syslog-share-audit (auto, 15min)
Vérifie le montage /mnt/syslog et la présence des flux de logs centralisés.
cluster-package-uniformity-audit (auto, 6h)
Contrôle l'homogénéité des paquets critiques sur les workers.
cluster-worker-baseline-audit (auto, 6h)
Contrôle régulier du socle système des workers.
Remplace : /etc/cron.d/e2scrub_all
self-audit (auto, 1h)
Auto-diagnostic complet : services Docker, endpoints API, tables DB,
modèles Ollama, connectivité Redis/Qdrant. Produit un rapport JSON.
#### Analysis (1 tâche)
syslog-health-summary (auto, 15min)
Résumé JSON du partage syslog pour les futures corrections
et optimisations autonomes par AISIA.
#### Backup (3 tâches)
sia-state-backup (auto, 24h)
Dump MariaDB + snapshots Qdrant vers NAS.
Script : deploy/cluster-maintenance/backup-aisia-state.sh
redis-backup (auto, 6h)
Trigger un BGSAVE Redis pour persister les données en mémoire
(conversations, billing, bot status, circuit breakers).
Commande : redis-cli -h ${BACKEND_REDIS_HOST} BGSAVE
backup-offsite (selon configuration)
Sauvegarde off-site des données critiques.
Script : deploy/cluster-maintenance/backup-offsite.sh
#### Maintenance (1 tâche)
cluster-image-refresh (manuel, destructif)
Rafraîchissement des images Docker sur les workers.
Remplace : 0 1 * docker image ls --format ... | sh
#### Intégrations (2 tâches)
integrations-health-check (auto, 1h)
Health check global sur toutes les intégrations actives déclarées
dans integrations.yaml. Détecte les régressions d'API et credentials expirés.
integrations-update-review (auto, 24h)
Affiche les intégrations dont la date next_review est dépassée.
Rappel de révision manuelle des versions API.
#### RGPD (1 tâche)
rgpd-data-purge (auto, 24h, destructif)
Supprime les comptes inactifs depuis plus de RGPD_USER_RETENTION_DAYS jours
et les entrées audit_log plus anciennes que RGPD_AUDIT_RETENTION_DAYS jours.
Conforme RGPD article 5(1)(e).
#### Synchronisation (1 tâche)
model-sync (manuel)
Interroge chaque provider cloud via /v1/models pour découvrir les nouveaux modèles.
Interroge Ollama via /api/tags pour les modèles locaux.
Met à jour providers.yaml et local_models.yaml.
Exécuté automatiquement par le bot toutes les 24h.
---
| Variable | Défaut | Description |
|---|---|---|
MAINTENANCE_SCHEDULER_ENABLED | false | Active le scheduler automatique |
MAINTENANCE_SCHEDULER_POLL_INTERVAL_S | 30 | Intervalle de vérification |
MAINTENANCE_SCHEDULER_MAX_CONCURRENT_TASKS | 2 | Tâches simultanées max |
MAINTENANCE_COMMAND_TIMEOUT_S | 900 | Timeout commande (15min) |
# Statut complet du scheduler
GET /admin/maintenance/status
Lancer une tâche manuellement
POST /admin/maintenance/tasks/{task_id}/run
Activer/désactiver une tâche
PUT /admin/maintenance/tasks/{task_id}/enabled
Body: {"enabled": true}
Recharger le catalogue
POST /admin/maintenance/reload
{
"enabled": true,
"running": true,
"leader": true,
"leader_instance_id": "uuid",
"catalog_path": "/app/maintenance_tasks.yaml",
"workspace_root": "/app",
"poll_interval_s": 30,
"max_concurrent_tasks": 2,
"task_count": 17,
"auto_enabled_tasks": 13,
"running_tasks": 1,
"last_tick_at": "2026-04-19T10:30:00Z",
"tasks": [...]
}
{
"task_id": "cluster-runtime-reconcile",
"title": "Reconcile Docker runtime on workers",
"enabled": true,
"auto_run": true,
"interval_s": 900,
"running": false,
"next_run_at": "2026-04-19T10:45:00Z",
"last_run": {
"run_id": "uuid",
"trigger": "scheduler",
"status": "success",
"started_at": "2026-04-19T10:30:00Z",
"finished_at": "2026-04-19T10:30:45Z",
"exit_code": 0,
"duration_ms": 45000,
"stdout_excerpt": "...",
"stderr_excerpt": ""
}
}
---
La tâche sia-state-backup exécute le script
deploy/cluster-maintenance/backup-aisia-state.sh une fois par jour.
Ce script effectue :
1. Dump MariaDB :
- mysqldump de la base aisia complète
- Compression gzip
- Stockage sur NAS /mnt/docker/AISIA/backups/
2. Snapshot Qdrant :
- Snapshot via l'API REST Qdrant (POST /collections/{name}/snapshots)
- Pour chaque collection : ai_responses, router_embeddings, eval_corpus,
mtp_knowledge, mtp_training_pairs
- Stockage sur NAS
# Depuis un backup compressé
gunzip < /mnt/docker/AISIA/backups/aisia_20260419.sql.gz | \
mysql -h 192.168.1.1 -u aisia -p aisia
# Via l'API REST Qdrant
curl -X PUT "http://qdrant:6333/collections/{name}/snapshots/recover" \
-H "Content-Type: application/json" \
-d '{"location": "/path/to/snapshot.snapshot"}'
---
La tâche redis-backup déclenche un BGSAVE Redis qui écrit
le dump RDB sur disque.
redis-cli -h aisia-core_redis BGSAVE
| Clé | Contenu | TTL |
|---|---|---|
aisia:conv:{user_id}:{conv_id} | Historique conversation | 1h |
aisia:billing:* | Compteurs billing | 90 jours |
aisia:bot:status | État du bot | variable |
aisia:maintenance:status | État maintenance | variable |
aisia:learning:status | État apprentissage | variable |
bandit:{provider_id} | État bandit | 24h |
cb:{provider_id} | État circuit breaker | 1h |
aisia:ai_rules | Cache guardrails | 300s |
aisia:rl:* | Compteurs rate limiting | 1h/24h |
oidc:state:* | États CSRF OIDC | 600s |
# Arrêter Redis
docker service scale aisia-core_redis=0
Copier le fichier dump.rdb
cp /mnt/docker/AISIA/backups/dump.rdb /data/redis/dump.rdb
Redémarrer Redis
docker service scale aisia-core_redis=1
---
Le script deploy/cluster-maintenance/backup-offsite.sh permet de copier
les backups vers un stockage externe (serveur distant, S3, etc.).
Les paramètres sont définis via des variables d'environnement :
BACKUP_OFFSITE_HOST : hôte distantBACKUP_OFFSITE_PATH : chemin de destinationBACKUP_OFFSITE_METHOD : méthode (rsync, scp, s3)cluster-docker-prune)
Cette tâche est désactivée par défaut (enabled: false, auto_run: false)
car elle est destructrice et peut supprimer des artefacts utiles au runtime.
# Déclenchement manuel via l'API
POST /admin/maintenance/tasks/cluster-docker-prune/run
Le script exécute docker system prune --all --volumes --force sur chaque
worker du cluster via SSH.
cluster-image-refresh)Également manuelle et destructrice, cette tâche met à jour les images Docker sur les workers.
1. Toujours vérifier l'état des services avant une purge
2. Planifier les purges en dehors des heures d'activité (nuit)
3. Vérifier les backups avant toute opération destructrice
4. Ne jamais activer auto_run: true sur les tâches destructives sans supervision
---
POST /admin/autonomy/reload
Authorization: Bearer TOKEN
Cette opération :
1. Invalide le cache providers et modèles
2. Ferme tous les adaptateurs de runtime existants
3. Relit local_models.yaml depuis le disque
4. Crée les nouvelles définitions de modèles
5. Initialise les nouveaux adaptateurs (Ollama, vLLM, llama.cpp, TGI)
6. Timeout global de 30 secondes
{
"available": true,
"model_count": 74,
"available_model_count": 12,
"runtimes": ["llama.cpp", "ollama", "tgi", "vllm"],
"reload_count": 3,
"last_reload_at": "2026-04-19T10:30:00Z",
"models": [...]
}
---
Impact : le Swarm perd son manager, les services continuent sur les workers mais ne peuvent pas être reconfigurés.
Procédure :
1. Redémarrer le manager physiquement ou via IPMI
2. Docker Swarm reprend automatiquement le contrôle
3. Vérifier les services : docker service ls
4. Régénérer la configuration Traefik : bash deploy/update-traefik-backend.sh
5. Vérifier le health : curl https://aisia.fr/health
Impact : les replicas sur ce worker sont redistribuées automatiquement par Docker Swarm (si d'autres noeuds sont disponibles).
Procédure :
1. Identifier le worker défaillant : docker node ls
2. Le redémarrer si possible
3. S'il ne revient pas, le retirer du Swarm : docker node rm
4. Vérifier que les replicas ont été redistribuées : docker service ps aisia_api
Impact : l'API fonctionne en mode dégradé (pas de persistance des conversations, pas d'authentification DB, pas de billing DB).
Procédure :
1. Vérifier le service : docker service ls | grep mariadb
2. Consulter les logs : docker service logs aisia-core_mariadb --tail 50
3. Si la base est corrompue, restaurer depuis le backup :
# Arrêter le service
docker service scale aisia-core_mariadb=0
# Restaurer le dump
gunzip < /mnt/docker/AISIA/backups/aisia_latest.sql.gz | \
mysql -u aisia -p aisia
# Relancer
docker service scale aisia-core_mariadb=1
4. Les tables sont recréées automatiquement au démarrage de l'API
(DDL idempotent CREATE TABLE IF NOT EXISTS)
Impact : fonctionnement dégradé avec fallback mémoire locale.
| Fonctionnalité | Avec Redis | Sans Redis |
|---|---|---|
| Bandit state | Cross-replica | Mémoire locale par replica |
| Circuit breaker | Cross-replica | Mémoire locale |
| Conversations cache | Redis rapide | DB uniquement |
| Rate limiting | Fonctionnel | Désactivé |
| Bot status | Distribué | Local uniquement |
| OIDC state CSRF | Valide | Non vérifié |
Impact : pas de RAG, pas de knowledge base, pas de stockage des paires d'entraînement.
Procédure :
1. Vérifier le service Qdrant
2. Redémarrer si nécessaire
3. Les collections sont recréées automatiquement au démarrage (_ensure_collections)
---
Les tâches d'audit suivantes s'exécutent automatiquement :
| Tâche | Fréquence | Vérifie |
|---|---|---|
self-audit | 1h | Services, API, DB, Ollama, Redis, Qdrant |
cluster-root-usage-audit | 1h | Occupation disque workers |
cluster-logging-audit | 30min | Uniformité syslog |
manager-syslog-share-audit | 15min | Partage syslog manager |
cluster-package-uniformity-audit | 6h | Paquets système |
cluster-worker-baseline-audit | 6h | Baseline workers |
La tâche rgpd-data-purge garantit la conformité avec l'article 5(1)(e)
du RGPD en supprimant automatiquement les données dépassant la durée de rétention.
Les résultats des audits sont :
aisia:maintenance:status)GET /admin/maintenance/statusQuand Redis est disponible, le MaintenanceScheduler utilise un mécanisme de leader election pour éviter l'exécution en double :
1. Chaque instance possède un instance_id unique (UUID)
2. L'élection utilise SET NX (set if not exists) sur la clé aisia:maintenance:leader
3. Le TTL du lock est max(poll_interval * 3, 30s)
4. Le leader renouvelle son lock à chaque tick
5. Si le leader tombe, une autre instance acquiert le lock après expiration du TTL
Le sémaphore limite le nombre de tâches exécutées simultanément
(défaut : 2 tâches max en parallèle via asyncio.Semaphore).
En l'absence de Redis, l'instance se considère comme leader et exécute les tâches localement. Il n'y a pas de coordination inter-replicas.
---
# Statut global
GET /admin/maintenance/status
Détail d'une tâche
GET /admin/maintenance/tasks/{task_id}
Les snapshots du scheduler sont publiés dans Redis :
aisia:maintenance:statusmax(poll_interval * 3, 180s)| Condition | Action |
|---|---|
running_tasks bloqué pendant >30min | Vérifier les tâches en cours |
last_tick_at dépasse 5 minutes | Le scheduler est peut-être arrêté |
Tâche self-audit échoue 3 fois | Investiguer le rapport |
| Tâche backup échoue | Vérifier l'accès NAS |
leader: false sur toutes les instances | Problème Redis ou élection |
Les résultats des tâches sont persistés en DB via la table aisia_maintenance_tasks :
task_id : identifiant de la tâcheenabled : état activé/désactivélast_status : dernier statut (success/failed/timeout)last_detail : extrait stdout/stderrupdated_at : date de dernière exécutionDocument AISIA v4.21.0