TheSocle en 5 minutes — ni Spring Batch, ni Temporal

Nos applications ont presque toutes la même forme. Elles tournent longtemps. Elles relèvent des flux, enrichissent des données, publient à heure fixe. Et, de plus en plus, un agent IA doit pouvoir leur demander quelque chose. Socle V005 est le framework Java écrit pour cette forme-là. Cet article en donne la carte : cinq mots, un worker réel, et ce que le framework ne fait pas.

Le problème

Dans une application Spring ordinaire, le travail de fond se disperse. Un @Scheduled ici, un thread lancé à la main là, un contrôleur écrit exprès pour déclencher un traitement. Personne ne sait dans quel ordre tout démarre, ni dans quel ordre tout s’arrête. Et le jour où un agent IA doit appeler ces traitements, il faut encore écrire une couche pour lui.

Socle V005 range tout cela sous une seule règle : chaque traitement est un worker, et un seul chef d’orchestre les fait vivre.

Cinq mots pour tout comprendre

Le Worker

Une unité de traitement, un fichier Java. Il a un cycle de vie explicite : initialize, start, doWork, stop. Il ne se planifie jamais lui-même.

Le MOP

Le Main Orchestrator Process. Il démarre les workers par priorité, appelle leur doWork au bon rythme, surveille leur santé, les redémarre, et les arrête dans l’ordre inverse.

Le KvBus

Le bus interne : des clés, des valeurs, et des sujets auxquels on publie et on s’abonne. En mémoire, ou sur Redis quand plusieurs instances doivent se parler.

L’Action

Une commande qu’un worker déclare une fois. Le framework l’expose en REST et, si MCP est activé, comme outil pour un agent IA. Aucun contrôleur à écrire.

La TechDB

Une base H2 embarquée, purement technique : états des workers, journaux, audit des actions. Les données métier vont ailleurs, en général dans PostgreSQL.

Un worker réel

Voici le moteur de diffusion de TheDiffuseur, en production. Chaque minute, il prend ce qui est dû et l’envoie. Il ne décide de rien d’autre.

@Override
public String getName() {
    return "diffusion_worker";
}

@Override
public String getSchedule() {
    return "* * * * *";
}

@Override
public void doWork() {
    dernierPassage = Instant.now();
    List<Long> dues = publications.cellesQuiSontDues(plafondParCycle);
    if (dues.isEmpty()) return;

    log.info("[worker:{}][step:cycle] {} cible(s) due(s)", getName(), dues.size());
    for (Long idCible : dues) {
        try {
            switch (publications.envoyer(idCible, signature)) {
                case PUBLIEE -> publiees.incrementAndGet();
                case ECHEC_TEMPORAIRE, ECHEC_DEFINITIF -> echecs.incrementAndGet();
                case DEJA_PRISE -> dejaPrises.incrementAndGet();
            }
        } catch (RuntimeException e) {
            // Une cible qui explose ne doit pas emporter les autres : le cycle continue.
            echecs.incrementAndGet();
            log.error("[worker:{}][step:cible][cible:{}] Échec non rattrapé", getName(), idCible, e);
        }
    }
}

Trois choses à remarquer :

  • Pas de boucle, pas de Thread.sleep. Le worker dit quand il veut travailler (getSchedule(), une expression cron à cinq champs). C’est le MOP qui l’appelle.
  • Une erreur ne tue pas le cycle. Une cible qui échoue est comptée ; les autres partent.
  • Deux instances ne publient pas deux fois. envoyer prend chaque cible par une écriture conditionnelle en base. La seconde instance voit DEJA_PRISE et passe à la suivante.

Le même worker déclare deux actions, get_status et forcer_un_cycle. Sans une ligne de plus, elles répondent en REST sur POST /admin/workers/diffusion_worker/actions/forcer_un_cycle, et un agent IA les voit comme l’outil MCP diffusion_worker__forcer_un_cycle.

@Override
public List<ActionMetadata> getActions() {
    return List.of(
            ActionMetadata.builder()
                    .name("get_status")
                    .description("Compteurs du moteur de diffusion")
                    .mode(ExecutionMode.SYNC)
                    .readOnly(true)
                    .build(),
            ActionMetadata.builder()
                    .name("forcer_un_cycle")
                    .description("Exécute un cycle immédiatement, sans attendre la minute suivante")
                    .mode(ExecutionMode.SYNC)
                    .readOnly(false)
                    .build());
}

Ni Spring Batch, ni Temporal

On nous pose souvent la question. La réponse tient dans un tableau.

Spring Batch Temporal Socle V005
Modèle des jobs découpés en étapes, par chunks des workflows dont l’historique est répliqué des workers qui tournent en continu
Exécution déclenchée, planifiée ou à la main pilotée par le moteur de workflow continue, et réactive aux événements
État un JobRepository en base durable et rejouable au mieux : TechDB et KvBus, sans rejeu
Exploitation une base à côté de l’application un cluster Temporal à opérer un JAR, une JVM

Si vous devez traiter des milliards de lignes avec reprise sur incident, prenez Spring Batch. Si un processus dure des semaines et doit survivre à tout, avec des tâches humaines, prenez Temporal ou Camunda. Socle vise autre chose : une application vivante, dans une seule JVM, qui réagit, décide et se laisse piloter par un agent.

Ce que Socle n’est pas

  • Pas un orchestrateur de conteneurs. Le MOP orchestre des workers dans une JVM, pas des services répartis.
  • Pas un ORM. Pas de JPA : du JDBC direct vers PostgreSQL.
  • Pas un remplaçant de Spring. Il s’appuie sur Spring Boot pour l’injection et la configuration.
  • Pas un framework Kafka. Il sait consommer Kafka, mais ce n’est pas son cœur.

Ce que ça donne en vrai

La version en service est la 5.8.6, sur Java 21 et Spring Boot 4.0.6. Le Hub TheSocle est lui-même une application Socle : 61 workers sur le Hub thesocle.net, relevés le 2026-09-23. La Veille, Entreprises, SmartDailyReach et TheDiffuseur sont construites de la même façon.

Chaque application sert son tableau de bord sur /dashboard, sur son propre port, et sa sonde de santé sur /actuator/health. Il n’y a plus de port dédié au tableau de bord.

À retenir

  • Un traitement = un worker ; le MOP seul le fait vivre.
  • Une action déclarée une fois sert en REST et en MCP.
  • Une JVM, pas un cluster : c’est un choix, avec ses limites.

Un programme à construire sur TheSocle ?

Retour en haut

Mentions légales · Confidentialité · Contact

© 2026 LMVI Conseil — SARL, SIREN 949 417 620 · [email protected]