<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rust Archives | Clever Cloud</title>
	<atom:link href="https://www.clever.cloud/fr/blog/tag/rust/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.clever.cloud/fr/blog/tag/rust/</link>
	<description>From Code to Product</description>
	<lastBuildDate>Wed, 15 Jul 2026 14:46:38 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://cdn.clever-cloud.com/uploads/2023/03/cropped-cropped-favicon-32x32.png</url>
	<title>Rust Archives | Clever Cloud</title>
	<link>https://www.clever.cloud/fr/blog/tag/rust/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Magnetar : un client Apache Pulsar en Rust conçu pour la simulation déterministe</title>
		<link>https://www.clever.cloud/fr/blog/engineering-fr/2026/07/15/magnetar-client-apache-pulsar-rust-simulation-deterministe/</link>
		
		<dc:creator><![CDATA[Florentin Dubois]]></dc:creator>
		<pubDate>Wed, 15 Jul 2026 14:46:37 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Rust]]></category>
		<guid isPermaLink="false">https://www.clever.cloud/?p=24982</guid>

					<description><![CDATA[<p><img width="2400" height="1065" src="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.07.15 Clever Cloud Bannière Blog Magnetar FR" decoding="async" fetchpriority="high" srcset="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png 2400w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1536x682.png 1536w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-2048x909.png 2048w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1368x607.png 1368w" sizes="(max-width: 2400px) 100vw, 2400px" /></p><!-- wp:paragraph -->
<p><a href="https://apple.github.io/foundationdb/testing.html">FoundationDB</a> a rendu cette idée célèbre. Au lieu de s'appuyer seulement sur des tests unitaires et des tests end-to-end sur un vrai cluster, le projet exécute des workloads distribués dans un monde simulé, où le temps, les fautes réseau, les pannes de processus et les décisions d'ordonnancement peuvent être explorés puis rejoués à partir d'une seed. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">TigerBeetle</a> pousse une discipline complémentaire : rendre les invariants explicites dans le code, vérifier en continu la forme de l'état et transformer une corruption silencieuse en panne locale et bruyante.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous appliquons cette direction à des logiciels d'infrastructure en Rust. <a href="https://github.com/PierreZ/moonpool">Moonpool</a>, développé par Pierre Zemb, donne aux systèmes Rust un environnement de simulation déterministe où le temps, le réseau, les tâches, l'aléa et le stockage peuvent être virtualisés derrière des traits de providers. <a href="https://github.com/CleverCloud/magnetar">Magnetar</a> est l'application de cette approche à un client <a href="https://pulsar.apache.org/">Apache Pulsar</a>. C’est d’ailleurs, l’approche que nous prenons au sein de notre reverse proxy <a href="https://www.clever.cloud/fr/blog/entreprise/2026/07/01/sozu-2-1-0-load-balancing-udp-edge-programmable/">Sōzu</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est un driver Apache Pulsar écrit en Rust, depuis zéro. Il repose sur un coeur protocolaire sans-io, un moteur de production Tokio et un moteur Moonpool pour la simulation déterministe. Cette première release publique s'adresse aux ingénieurs qui veulent essayer Magnetar, évaluer son architecture, comparer son comportement avec les clients Pulsar existants et contribuer à structurer un écosystème Pulsar Rust plus solide.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'objectif n'est pas seulement d'exposer une API Rust autour de Pulsar. L'objectif est de construire un client dont les comportements difficiles peuvent être inspectés, rejoués et forcés à échouer avant que la production ne s'en charge.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Un client Pulsar fait partie du système distribué</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>On pourrait être tenté de considérer une bibliothèque cliente comme la partie simple d'un système distribué. Le broker porterait la réplication, le stockage, l'ownership et la coordination. Le client se contenterait de se connecter, d'envoyer des messages, d'en recevoir et de les acquitter.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette vision ne tient pas face à un vrai client Apache Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client Pulsar sérieux doit gérer les producers, consumers, readers, topics partitionnés, consumers multi-topics, subscriptions par pattern, transactions, schémas, authentification, routage proxy, lookup broker, failover de cluster, reconnect, backoff, batching, chunking, ack grouping, suivi des messages non acquittés, negative acknowledgements, retry-letter et dead-letter flows, observabilité et une longue liste de Pulsar Improvement Proposals.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les bugs difficiles ne viennent pas seulement d'une commande mal encodée. Ils viennent souvent du temps et de l'ordre. Un broker tombe pendant qu'un publish est en vol. Une reconnexion arrive alors qu'un consumer a des acknowledgements en attente. Un refresh de token se produit pendant un reset de session. Un lookup via proxy pointe vers un nouveau broker alors que l'ancienne connexion se vide encore. Un topic migre et le client doit reconstruire assez d'état pour continuer sans prétendre que l'ancienne session existe toujours.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela signifie qu'un client Pulsar n'est pas seulement un wrapper pratique autour d'une socket. Il fait partie du système distribué. Il possède un état qui doit rester cohérent pendant que le monde autour de lui change.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si cet état est caché dans des tâches runtime, des files de channels, des horloges implicites et des accidents de timing, alors le client devient plus difficile à raisonner précisément au moment où cette précision compte le plus. Magnetar part de l'hypothèse inverse : rendre l'état protocolaire explicite, le piloter à travers des frontières étroites et garder l'I/O à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">De l'écosystème Pulsar Rust à Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar vient d'une expérience concrète avec l'écosystème Pulsar Rust, notamment la maintenance et l'usage de <a href="https://github.com/streamnative/pulsar-rs">pulsar-rs</a>. Ce travail compte. Il a donné aux utilisateurs Rust un client Apache Pulsar et a créé le contexte pratique dans lequel l'étape suivante pouvait être évaluée.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar n'est pas une critique de ce qui existait avant lui. C'est une continuation du même écosystème, avec un point de départ architectural différent. Après avoir travaillé sur des usages Pulsar réels, la direction est devenue plus claire : un driver Pulsar Rust doit rendre la frontière protocole/runtime plus nette, rendre les comportements difficiles reproductibles, suivre la parité explicitement et faire de la testabilité une contrainte de conception.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar ne commence pas par le builder public. Il commence par le protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API utilisateur compte, et cette première release expose déjà une surface large. Mais pour un client distribué, la question plus profonde est ce qui se passe sous cette API lorsque le broker bouge, que la connexion tombe, que l'horloge avance, qu'un timeout se déclenche, qu'une subscription est reconstruite ou que la même trace est rejouée sous un autre runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Le coeur sans-io</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le coeur de Magnetar est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-proto">magnetar-proto</a>. C'est une machine d'état protocolaire synchrone. Elle n'a pas de socket. Elle ne dépend pas de Tokio. Elle ne lance pas de tâches. Elle n'utilise pas async. Elle ne lit pas l'horloge hôte sur le chemin chaud du protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sa forme suit la même idée générale qui a rendu <a href="https://github.com/quinn-rs/quinn/tree/main/quinn-proto">quinn-proto</a> influent dans le monde réseau Rust : injecter des octets, récupérer des octets à transmettre, récupérer des événements sémantiques et demander à la machine d'état quand son prochain timer expire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Conceptuellement, l'interface ressemble à ceci :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>&gt; connection.handle_bytes(now, bytes);

connection.poll_transmit(&amp;mut out);
connection.poll_event();
connection.poll_timeout();</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette petite forme est un grand choix d'architecture.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>handle_bytes permet à un moteur d'injecter les octets du wire dans la machine d'état. poll_transmit draine les frames sortantes. poll_event produit les événements sémantiques auxquels le runtime doit réagir : challenges d'authentification, résultats de lookup, checksum mismatch, signaux de reconnexion ou transitions protocolaire. poll_timeout permet au runtime de savoir quand réveiller la machine d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La machine d'état ne décide pas d'où viennent les octets. Elle ne sait pas si le réseau est un vrai stream TCP, un stream TLS, un pipe d'octets dans un simulateur ou un broker scripté dans un harnais différentiel. Elle ne décide pas non plus ce que "maintenant" veut dire. Le moteur lui passe le temps.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les traits publics de magnetar-proto suivent la même règle. Ce ne sont pas des services runtime cachés derrière des callbacks async. Ce sont de petits contrats protocolaires, placés aux endroits où la machine d'état a besoin d'une décision ou d'une transformation : <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/auth.rs">AuthProvider</a> produit les octets d'authentification, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/schema/mod.rs">Schema</a> définit l'encodage, le décodage, les données de schéma et les hooks de schéma résolu par le broker, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/crypto.rs">MessageEncryptor et MessageDecryptor</a> décrivent la crypto de payload sur des octets et de la metadata de message, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/service_url.rs">ServiceUrlProvider</a> expose l'URL de service courante pour le failover, et <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/health_probe.rs">HealthProbe</a> utilise un contrat de type poll au lieu d'attacher le crate protocolaire à un runtime async. Le motif est volontaire : le coeur protocolaire peut demander des faits, des octets ou un état de readiness, tandis que l'I/O, le cache, le refresh, les probes réseau et le scheduler restent à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette séparation n'est pas seulement une affaire de propreté. C'est ce qui rend le protocole testable sans broker, sans socket et sans runtime async. Un bug protocolaire peut être réduit à une fixture : injecter ces octets à cet instant, récupérer ces sorties, vérifier cet event stream et rejouer la même séquence.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour un client Apache Pulsar, cela compte parce que le protocole wire ne se limite pas au chemin heureux. Il comprend la création de producers, la subscription de consumers, les acks, nacks, transactions, erreurs broker, redirects, challenges d'authentification, migrations de topics, markers de replicated subscriptions, metadata de schémas, batching, chunking et chemins de fermeture. Chacun de ces éléments porte de l'état. Chaque transition d'état est plus facile à raisonner lorsqu'elle n'est pas mélangée aux lectures de socket, au scheduling de tâches et aux wakeups spécifiques d'un runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">L'interdiction des channels comme contrainte d'architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar fait aussi un choix Rust async peu courant : les primitives de channels sont interdites dans le workspace.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'architecture directe d'un client réseau ressemble souvent à ceci : future producer vers channel, channel vers driver task, driver task vers channel, channel vers future consumer. Cela peut fonctionner, mais cela disperse l'état entre des files et des tâches. La backpressure devient implicite. Les sémantiques de fermeture dépendent de la bibliothèque de channel. Des futures abandonnées peuvent laisser des messages dans des endroits difficiles à inspecter. La question de debug devient : où est passé ce message ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar utilise un autre motif. L'état vit dans la machine d'état protocolaire et dans la connexion partagée détenue par le runtime. Les futures utilisateur enregistrent des wakers dans des slabs indexés par identifiants d'opération. Le driver possède la boucle d'I/O, injecte les octets dans la machine d'état, draine les frames sortantes et réveille les futures correspondantes lorsque les outcomes arrivent.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce n'est pas une interdiction esthétique des channels. C'est une manière de garder la propriété de l'état explicite. Lorsque le driver reconstruit des producers après une reconnexion, lorsqu'un consumer attend un message, lorsqu'un ack outcome est livré ou lorsqu'une opération en attente échoue parce qu'une session a disparu, l'état pertinent est dans la machine d'état et peut y être inspecté.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce design a des compromis. Il met plus de pression sur la correction de la machine d'état. Il impose un ordre de locks précis. Il demande aux reviewers de comprendre l'enregistrement des wakers et les chemins de réveil. Mais il rend aussi le comportement beaucoup plus facile à simuler, rejouer et comparer entre runtimes.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Deux moteurs, une machine d'état</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar livre deux moteurs qui pilotent le même coeur protocolaire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur par défaut est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-tokio">magnetar-runtime-tokio</a>. C'est le chemin d'exécution de production : TCP, TLS via tokio-rustls, tâches driver, temps réel, vraies sockets et surface publique PulsarClient que la plupart des utilisateurs rencontreront en premier.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le second moteur est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-moonpool">magnetar-runtime-moonpool</a>. Il pilote la même machine d'état magnetar-proto::Connection à travers des providers Moonpool. Au lieu d'inscrire le runtime en dur, Moonpool expose des traits de providers pour le réseau, le temps, le spawning de tâches, l'aléa et le stockage. Avec un bundle de providers proche de la production, le moteur peut exécuter de vraies I/O. Avec des providers de simulation, ces mêmes catégories peuvent être virtualisées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est là que la simulation déterministe devient pratique. Le client peut être piloté dans un monde où le temps avance sous contrôle, où les livraisons réseau peuvent être réordonnées ou interrompues, où les tâches s'exécutent sous un scheduler déterministe, où l'aléa est seedé et où les pannes peuvent être rejouées depuis la même seed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas un mock. Un mock remplace généralement un composant par un comportement simplifié. C'est utile pour beaucoup de tests unitaires, mais ce n'est pas la même chose que d'exercer un vrai client dans des interleavings difficiles.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas non plus un test end-to-end classique. Un e2e exécute le vrai système, ce qui est indispensable, mais il utilise souvent du temps réel, un vrai réseau et des pannes difficiles à reproduire une fois le timing passé.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool occupe un autre espace. Il garde le code proche du chemin réel d'exécution tout en virtualisant les providers qui rendent le comportement distribué difficile à reproduire. Le but n'est pas d'éviter les e2e. Le but est d'ajouter un régime où les pannes ne sont plus des anecdotes. Elles deviennent des seeds.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur Moonpool de Magnetar utilise la même machine d'état protocolaire que le moteur Tokio. Le chemin TLS est lui aussi piloté de façon à préserver la frontière de simulation : au lieu de s'appuyer sur tokio-rustls, le moteur Moonpool pilote directement rustls::ClientConnection au-dessus du pipe d'octets. Cela maintient les handshakes TLS sous le même contrôle déterministe que le reste du réseau simulé.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Tests différentiels : faire converger les moteurs</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Deux moteurs ne sont utiles que s'ils ne deviennent pas silencieusement deux clients différents.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar inclut donc un harnais différentiel. Il exécute une trace, par exemple connect, open producer, send, subscribe, receive, ack, seek et close, contre les moteurs Tokio et Moonpool, puis compare les event streams visibles par l'utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que le moteur Moonpool sert à trouver des bugs difficiles à exposer avec du temps réel et de vraies sockets. Pour que cette recherche ait du sens, le moteur simulé doit rester aligné avec le moteur de production à la frontière utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si Tokio et Moonpool divergent, le simulateur devient moins fiable. Si le harnais différentiel les maintient alignés, alors une seed rouge dans le monde simulé pointe beaucoup plus probablement vers une propriété réelle du client, et non vers une implémentation séparée réservée aux tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est aussi pour cela que la politique de validation de Magnetar est stricte sur la couverture cross-runtime. Les changements comportementaux doivent exercer la couche sans-io, le runtime Tokio, le runtime Moonpool, l'équivalence différentielle et la surface e2e lorsque c'est applicable. C'est plus de travail qu'un seul test unitaire. C'est aussi le coût pour faire de la simulation déterministe un vrai outil d'ingénierie, pas une expérience annexe.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La parité Java comme contrat de crédibilité</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La simulation ne remplace pas la largeur fonctionnelle. Elle rend cette largeur moins fragile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Apache Pulsar possède un <a href="https://pulsar.apache.org/docs/">client Java</a> mature, et pour beaucoup d'utilisateurs ce client définit ce que signifie "un client Pulsar". Le produce/consume de base ne suffit pas. Un client crédible doit couvrir les comportements sur lesquels les applications s'appuient : batching, compression, transactions, schémas, topics partitionnés, consumers multi-topics et par pattern, retries, dead-letter flows, providers d'authentification, support proxy, failover, opérations admin et PIPs qui structurent les usages modernes de Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar suit la parité avec le client Java comme un contrat public. Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> porte la matrice de parité et le statut moteur par moteur. L'article n'a pas besoin de recopier cette matrice, mais son existence est importante. Elle donne aux utilisateurs un moyen d'évaluer le projet comme client Pulsar, et non comme une expérience étroite autour d'un seul chemin heureux.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi la première release publique de Magnetar est plus large qu'une démo minimale. Elle inclut la fondation protocolaire, la façade publique, les moteurs runtime, le support admin, les providers d'authentification, la crypto de messages, le travail CLI, les hooks d'observabilité et une liste croissante de surfaces PIP.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La raison de suivre la parité est simple : les utilisateurs ne choisissent pas une bibliothèque cliente uniquement parce que son architecture interne est élégante. Ils la choisissent parce qu'elle peut représenter le système qu'ils exécutent réellement. L'architecture rend cette surface maintenable. La parité la rend utile.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Au-delà de la production et de la consommation</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>L'expression "client Pulsar" peut masquer une large surface fonctionnelle. Vus de l'extérieur, les premiers exemples paraissent généralement modestes : construire un client, créer un producer, envoyer un payload, souscrire avec un consumer, recevoir un message, l'acquitter. Ces exemples sont utiles parce qu'ils montrent le point d'entrée. Ils ne suffisent pas à évaluer le client.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les vraies applications Pulsar dépendent de comportements qui n'apparaissent qu'une fois la première démo fonctionnelle. Un producer peut avoir besoin de batching, de compression, de chunking, de modes d'accès, de sequence ids, de timeouts d'envoi, de propriétés par message, de transactions, d'interceptors et de statistiques de latence. Un consumer peut avoir besoin de batch receive, d'acquittements cumulatifs, d'acquittements par index de batch, de nack backoff, de gestion des timeouts d'ack, de retry topics, de dead-letter topics, de seek, de pause/resume, de modes de souscription et de comportements par partition. Les applications avec des schémas stricts ont besoin d'Avro, de JSON, de Protobuf, de Protobuf-native, de KeyValue, de schémas primitifs et de la sémantique de résolution de schéma côté broker. Les déploiements avec des exigences de sécurité ont besoin d'authentification par token, de mTLS, d'OAuth2, de SASL, de Kerberos/GSSAPI, d'Athenz, de choix de provider TLS, et d'un moyen de raisonner sur le comportement de la crypto sans forcer chaque build à embarquer tous les providers.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces fonctionnalités ne sont pas des cases à cocher indépendantes. Elles interagissent. Le batching interagit avec la compression et les timeouts d'envoi. Le chunking interagit avec les sequence ids et la redélivrance. Les transactions interagissent avec les acquittements. La reconnexion interagit avec les producers, les consumers, les lookups, le routage proxy et le failover. L'observabilité doit décrire le comportement sans laisser fuiter de secrets ni noyer les opérateurs en période de churn.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi le travail fonctionnel et le travail d'architecture de Magnetar sont liés. Plus la surface devient complète, plus il est important que l'état protocolaire soit explicite et que la frontière avec le runtime reste étroite. Un client large bâti sur un état accidentel devient plus difficile à maintenir à mesure qu'il devient plus utile. Un client large bâti sur un état rejouable donne aux mainteneurs une meilleure chance d'empêcher la croissance fonctionnelle de se transformer en comportement caché.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La validation comme architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La stratégie de test de Magnetar est volontairement stratifiée, parce que chaque couche attrape une classe différente de bugs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La couche sans-io permet de tester le comportement protocolaire sans sockets ni tâches async. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">documentation de test du projet</a> mentionne aujourd'hui plus de 270 tests unitaires dans magnetar-proto. Ces tests exercent directement la machine d'état : octets en entrée, événements en sortie, buffers de transmission en sortie, transitions d'état vérifiées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'intégration runtime exercent la colle que les tests purement protocolaires ne peuvent pas couvrir. Les moteurs Tokio et Moonpool ont chacun leur surface d'intégration, et le projet impose une parité runtime afin qu'un moteur ne prenne pas silencieusement du retard sur l'autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le pack de chaos déterministe cible les ordonnancements de panne qui ont motivé l'architecture : reconnect, failover, timers en horloge virtuelle, ordre des handshakes TLS, publishes en vol, migration de broker et comportements réseau adversariaux. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> décrit un sweep Moonpool quotidien avec 128 seeds aléatoires fraîchement générées en parallèle. Le chiffre compte moins que ce qu'il représente : le client est poussé dans des ordonnancements qu'un humain n'écrirait pas à la main.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'équivalence différentielle comparent les deux mondes runtime. Ils posent une question directe : si la même trace est exécutée dans Tokio et Moonpool, l'utilisateur observe-t-il le même comportement ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests end-to-end restent nécessaires. Ils gardent Magnetar honnête face à un vrai broker Apache Pulsar. La simulation rend des pannes reproductibles, mais elle ne remplace pas la compatibilité avec le système que les utilisateurs déploient.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ensemble, ces couches ne sont pas une cérémonie. Elles font partie de l'architecture. Le but n'est pas d'accumuler de grands nombres de tests. Le but est d'appliquer la pression de validation exactement là où les clients distribués échouent : état protocolaire, frontières runtime, logique de reconnexion, timing, équivalence et comportement face à un vrai broker.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que la reproductibilité change concrètement</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La valeur pratique de la simulation déterministe n'est pas seulement de rendre les tests plus sophistiqués. Elle change la boucle de debug.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lorsqu'un test end-to-end traditionnel échoue à cause du timing, la première question est souvent de savoir si l'échec est reproductible. S'il ne l'est pas, on ajoute des sleeps, des logs, des timeouts plus larges ou des boucles de retry. Certaines de ces modifications sont utiles. Beaucoup ne font que déplacer la panne ailleurs. La panne reste une histoire : "on l'a vue une fois en CI".</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Avec une simulation déterministe, la panne doit devenir un artefact. Cet artefact est une seed, une trace et une transition d'état rejouable. La question passe de "peut-on la refaire apparaître ?" à "quel invariant cet ordonnancement a-t-il violé ?"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette différence compte pour une bibliothèque cliente. Les bugs de client se trouvent souvent à la frontière entre le code utilisateur et le broker. Ils sont faciles à attribuer au mauvais endroit. Un publish peut échouer parce que le broker a fermé la connexion, parce que le client a perdu un outcome, parce que le chemin de reconnexion a reconstruit le producer trop tard, parce qu'un ack a réveillé le mauvais waiter, parce qu'un timeout a frappé un état de session périmé, ou parce que la tâche runtime est morte après que le protocole a déjà changé d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si tout ce comportement est dispersé entre des tâches, des channels, des timers et des sockets, un rapport de panne est difficile à réduire. Si la machine d'état protocolaire est explicite, si la frontière runtime est étroite et si la même séquence peut être rejouée avec des providers contrôlés, le rapport devient beaucoup plus petit : cette seed, cette trace, cet ordre d'événements, cet invariant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar traite la reproductibilité comme une partie du design du client. Le but n'est pas seulement de trouver plus de bugs. Le but est que les bugs trouvés coûtent moins cher à comprendre et soient plus sûrs à corriger.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela change aussi la revue de code. Un reviewer peut demander si un comportement est couvert à la bonne couche. Est-ce une transition protocolaire pure ? Alors le test sans-io doit injecter des octets et vérifier des événements. Est-ce de la colle runtime ? Alors Tokio et Moonpool doivent avoir une couverture équivalente. Est-ce un comportement observable partagé par les deux moteurs ? Alors le harnais différentiel doit comparer les event streams. Est-ce de la compatibilité broker ? Alors un e2e doit toucher un vrai broker Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces questions sont plus précises que "a-t-on ajouté des tests ?" Elles relient le test au modèle de panne.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Par où commencer la lecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pour les ingénieurs qui découvrent Magnetar, le meilleur point d'entrée n'est pas un fichier unique. C'est la relation entre les documents et le code.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> donne la surface publique : ce que le client expose, quelles fonctionnalités sont implémentées, comment la matrice de parité Java est suivie, quels PIPs sont supportés et comment les deux moteurs sont positionnés. C'est le contrat utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> explique la forme située sous ce contrat. Il montre la topologie de crates, le sens des dépendances, la frontière sans-io, la boucle driver, le modèle d'événements, les chemins producer et consumer, les moteurs runtime, les sites TLS, les schémas, la couverture PIP et la stratégie de validation. C'est la carte du système.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">série d'ADR</a> explique pourquoi le système a cette forme. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">ADR-0004</a> documente la séparation sans-io. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0003-no-channels-rule.md">ADR-0003</a> documente l'interdiction des channels. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0011-clock-injection-sans-io.md">ADR-0011</a> documente l'injection d'horloge. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">ADR-0010</a> documente la décision de parité Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0019-engine-scope-and-moonpool-parity.md">ADR-0019</a> documente la relation entre le moteur de production Tokio et le moteur Moonpool par rapport à cet objectif de parité. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">ADR-0024</a> documente la politique de test cross-runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que Magnetar n'est volontairement pas seulement un dépôt de code. C'est un ensemble de décisions d'ingénierie avec une trace publique. Si vous n'êtes pas d'accord avec le design, les ADR donnent la bonne surface de discussion. Si vous voulez contribuer une fonctionnalité, la matrice de parité et la politique de validation indiquent ce que "terminé" veut dire. Si vous voulez évaluer le travail de simulation, la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> et le harnais différentiel montrent comment le même coeur protocolaire est piloté dans plusieurs mondes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette première release doit donc se lire de deux manières. Comme utilisateur Pulsar, regardez la surface cliente et la matrice de parité. Comme ingénieur infrastructure Rust, regardez la frontière de machine d'état et la stratégie de simulation. Ce qui rend Magnetar intéressant, c'est que ces deux lectures sont censées se renforcer.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que donne la première release publique</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Cette première release publique est un point d'entrée technique. Elle s'adresse aux ingénieurs qui veulent essayer Magnetar, lire l'architecture, inspecter les ADR, comparer le comportement avec les clients Pulsar existants et contribuer à structurer l'écosystème Pulsar Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API cliente de haut niveau commence par une forme attendue :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>let client = PulsarClient::builder()
    .service_url("pulsar://localhost:6650")
    .build()
    .await?;

let producer = client
    .producer("persistent://public/default/orders")
    .create()
    .await?;</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette API est importante, parce que le client doit être utilisable. Mais la release est aussi une invitation à inspecter les couches inférieures. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> pour la matrice fonctionnelle. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> pour le design sans-io. Lire les <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">ADR</a> pour les décisions derrière l'interdiction des channels, les moteurs remplaçables, l'injection d'horloge, la parité Java, la parité Moonpool, les choix de providers TLS et la validation cross-runtime. Lire la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> si la simulation déterministe appliquée à un vrai client réseau vous intéresse.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le point important pour cet article est la direction : Magnetar est public pour que les ingénieurs puissent évaluer à la fois la surface cliente et le modèle d'ingénierie qui la porte.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Vous pouvez consulter la première release publique de Magnetar <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.0.0">v1.0.0</a>, ainsi que la dernière release à ce jour, la version <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.2.0">v1.2.0</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Pourquoi cela dépasse Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar est un client Apache Pulsar. C'est aussi un exemple concret de la manière dont nous voulons construire davantage de logiciel d'infrastructure en Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les systèmes distribués échouent par transitions d'état. Certaines de ces transitions sont évidentes et faciles à tester. Beaucoup ne le sont pas. Elles apparaissent lorsque le temps avance au mauvais endroit, lorsqu'un retry chevauche un chemin de fermeture, lorsqu'un broker coupe une connexion après avoir accepté une partie de la session, lorsqu'un callback est enregistré juste après une notification, ou lorsqu'un chemin de reconnexion reconstruit un handle mais pas un autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>On peut essayer de traquer ces bugs après coup. C'est parfois inévitable. Mais l'architecture peut rendre cette traque plus facile ou plus difficile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client avec un coeur protocolaire pur, des événements explicites, du temps injecté, une I/O remplaçable, des seeds déterministes et une comparaison cross-runtime donne de meilleurs outils aux ingénieurs. Il permet de réduire une panne à une trace. Il permet de rejouer cette trace. Il permet de demander si une panne simulée correspond au runtime de production. Il permet d'ajouter un invariant là où une dérive silencieuse de l'état pouvait se cacher.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la direction prise par Magnetar. Rendre le protocole explicite. Rendre le runtime remplaçable. Rendre les pannes reproductibles. Faire de la correction quelque chose que le code doit démontrer en continu.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Merci à Pierre Zemb pour Moonpool et pour cette direction de simulation déterministe en Rust, ainsi qu'aux contributeurs et mainteneurs de l'écosystème Pulsar Rust dont le travail a rendu l'étape suivante possible.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est open source. Le code, les notes d'architecture, les ADR et la documentation vivent sur <a href="https://github.com/CleverCloud/magnetar">github.com/CleverCloud/magnetar</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:html -->
<hr style="border: none; height: 1px; background-color: #ccc; margin: 32px 0;">
<!-- /wp:html -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Magnetar</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Dépôt Magnetar</strong>. Dépôt public du client Apache Pulsar Rust. <a href="https://github.com/CleverCloud/magnetar">https://github.com/CleverCloud/magnetar</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>README Magnetar</strong>. Surface publique, matrice de parité Java, PIPs supportés, couverture par moteur et statut. <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">https://github.com/CleverCloud/magnetar/blob/main/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Architecture Magnetar</strong>. Rationale sans-io, topologie de crates, driver loop, machine d'état protocolaire et tests. <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Index de documentation Magnetar</strong>. Moteur Moonpool, testing, CLI, observabilité, logging, features PIP. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/README.md">https://github.com/CleverCloud/magnetar/blob/main/docs/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation du moteur Moonpool</strong>. Moteur de simulation déterministe, chaos pack, harnais différentiel, modèle de providers. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de test</strong>. Catégories de tests et commandes de validation. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0004</strong>. magnetar-proto sans-io et moteurs d'I/O remplaçables. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0010</strong>. Parité complète avec le client Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0024</strong>. Politique de tests et couverture cross-runtime. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Écosystème</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>pulsar-rs</strong>. Client Apache Pulsar Rust existant. <a href="https://github.com/streamnative/pulsar-rs">https://github.com/streamnative/pulsar-rs</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Apache Pulsar</strong>. Plateforme distribuée de messaging et streaming. <a href="https://pulsar.apache.org/">https://pulsar.apache.org/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Client Java Apache Pulsar</strong>. Surface de référence pour de nombreux utilisateurs Pulsar. <a href="https://pulsar.apache.org/docs/">https://pulsar.apache.org/docs/</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Simulation déterministe</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>FoundationDB testing</strong>. Lignée de la simulation déterministe et de l'injection de fautes. <a href="https://apple.github.io/foundationdb/testing.html">https://apple.github.io/foundationdb/testing.html</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle TigerStyle</strong>. Style d'ingénierie centré sur les assertions. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle VOPR</strong>. Approche de simulation testing. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Dépôt Moonpool</strong>. Simulation déterministe pour systèmes Rust, développée par Pierre Zemb. <a href="https://github.com/PierreZ/moonpool">https://github.com/PierreZ/moonpool</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>moonpool-sim</strong>. Crate du moteur de simulation Moonpool. <a href="https://crates.io/crates/moonpool-sim">https://crates.io/crates/moonpool-sim</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->]]></description>
										<content:encoded><![CDATA[<p><img width="2400" height="1065" src="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="2026.07.15 Clever Cloud Bannière Blog Magnetar FR" decoding="async" srcset="https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr.png 2400w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-300x133.png 300w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1024x454.png 1024w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-768x341.png 768w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1536x682.png 1536w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-2048x909.png 2048w, https://cdn.clever-cloud.com/uploads/2026/07/2026-07-15-clever-cloud-banniere-blog-magnetar-fr-1368x607.png 1368w" sizes="(max-width: 2400px) 100vw, 2400px" /></p><!-- wp:paragraph -->
<p><a href="https://apple.github.io/foundationdb/testing.html">FoundationDB</a> a rendu cette idée célèbre. Au lieu de s'appuyer seulement sur des tests unitaires et des tests end-to-end sur un vrai cluster, le projet exécute des workloads distribués dans un monde simulé, où le temps, les fautes réseau, les pannes de processus et les décisions d'ordonnancement peuvent être explorés puis rejoués à partir d'une seed. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">TigerBeetle</a> pousse une discipline complémentaire : rendre les invariants explicites dans le code, vérifier en continu la forme de l'état et transformer une corruption silencieuse en panne locale et bruyante.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Chez Clever Cloud, nous appliquons cette direction à des logiciels d'infrastructure en Rust. <a href="https://github.com/PierreZ/moonpool">Moonpool</a>, développé par Pierre Zemb, donne aux systèmes Rust un environnement de simulation déterministe où le temps, le réseau, les tâches, l'aléa et le stockage peuvent être virtualisés derrière des traits de providers. <a href="https://github.com/CleverCloud/magnetar">Magnetar</a> est l'application de cette approche à un client <a href="https://pulsar.apache.org/">Apache Pulsar</a>. C’est d’ailleurs, l’approche que nous prenons au sein de notre reverse proxy <a href="https://www.clever.cloud/fr/blog/entreprise/2026/07/01/sozu-2-1-0-load-balancing-udp-edge-programmable/">Sōzu</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est un driver Apache Pulsar écrit en Rust, depuis zéro. Il repose sur un coeur protocolaire sans-io, un moteur de production Tokio et un moteur Moonpool pour la simulation déterministe. Cette première release publique s'adresse aux ingénieurs qui veulent essayer Magnetar, évaluer son architecture, comparer son comportement avec les clients Pulsar existants et contribuer à structurer un écosystème Pulsar Rust plus solide.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'objectif n'est pas seulement d'exposer une API Rust autour de Pulsar. L'objectif est de construire un client dont les comportements difficiles peuvent être inspectés, rejoués et forcés à échouer avant que la production ne s'en charge.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Un client Pulsar fait partie du système distribué</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>On pourrait être tenté de considérer une bibliothèque cliente comme la partie simple d'un système distribué. Le broker porterait la réplication, le stockage, l'ownership et la coordination. Le client se contenterait de se connecter, d'envoyer des messages, d'en recevoir et de les acquitter.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette vision ne tient pas face à un vrai client Apache Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client Pulsar sérieux doit gérer les producers, consumers, readers, topics partitionnés, consumers multi-topics, subscriptions par pattern, transactions, schémas, authentification, routage proxy, lookup broker, failover de cluster, reconnect, backoff, batching, chunking, ack grouping, suivi des messages non acquittés, negative acknowledgements, retry-letter et dead-letter flows, observabilité et une longue liste de Pulsar Improvement Proposals.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les bugs difficiles ne viennent pas seulement d'une commande mal encodée. Ils viennent souvent du temps et de l'ordre. Un broker tombe pendant qu'un publish est en vol. Une reconnexion arrive alors qu'un consumer a des acknowledgements en attente. Un refresh de token se produit pendant un reset de session. Un lookup via proxy pointe vers un nouveau broker alors que l'ancienne connexion se vide encore. Un topic migre et le client doit reconstruire assez d'état pour continuer sans prétendre que l'ancienne session existe toujours.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela signifie qu'un client Pulsar n'est pas seulement un wrapper pratique autour d'une socket. Il fait partie du système distribué. Il possède un état qui doit rester cohérent pendant que le monde autour de lui change.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si cet état est caché dans des tâches runtime, des files de channels, des horloges implicites et des accidents de timing, alors le client devient plus difficile à raisonner précisément au moment où cette précision compte le plus. Magnetar part de l'hypothèse inverse : rendre l'état protocolaire explicite, le piloter à travers des frontières étroites et garder l'I/O à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">De l'écosystème Pulsar Rust à Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar vient d'une expérience concrète avec l'écosystème Pulsar Rust, notamment la maintenance et l'usage de <a href="https://github.com/streamnative/pulsar-rs">pulsar-rs</a>. Ce travail compte. Il a donné aux utilisateurs Rust un client Apache Pulsar et a créé le contexte pratique dans lequel l'étape suivante pouvait être évaluée.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar n'est pas une critique de ce qui existait avant lui. C'est une continuation du même écosystème, avec un point de départ architectural différent. Après avoir travaillé sur des usages Pulsar réels, la direction est devenue plus claire : un driver Pulsar Rust doit rendre la frontière protocole/runtime plus nette, rendre les comportements difficiles reproductibles, suivre la parité explicitement et faire de la testabilité une contrainte de conception.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar ne commence pas par le builder public. Il commence par le protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API utilisateur compte, et cette première release expose déjà une surface large. Mais pour un client distribué, la question plus profonde est ce qui se passe sous cette API lorsque le broker bouge, que la connexion tombe, que l'horloge avance, qu'un timeout se déclenche, qu'une subscription est reconstruite ou que la même trace est rejouée sous un autre runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Le coeur sans-io</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Le coeur de Magnetar est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-proto">magnetar-proto</a>. C'est une machine d'état protocolaire synchrone. Elle n'a pas de socket. Elle ne dépend pas de Tokio. Elle ne lance pas de tâches. Elle n'utilise pas async. Elle ne lit pas l'horloge hôte sur le chemin chaud du protocole.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Sa forme suit la même idée générale qui a rendu <a href="https://github.com/quinn-rs/quinn/tree/main/quinn-proto">quinn-proto</a> influent dans le monde réseau Rust : injecter des octets, récupérer des octets à transmettre, récupérer des événements sémantiques et demander à la machine d'état quand son prochain timer expire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Conceptuellement, l'interface ressemble à ceci :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>&gt; connection.handle_bytes(now, bytes);

connection.poll_transmit(&amp;mut out);
connection.poll_event();
connection.poll_timeout();</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette petite forme est un grand choix d'architecture.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>handle_bytes permet à un moteur d'injecter les octets du wire dans la machine d'état. poll_transmit draine les frames sortantes. poll_event produit les événements sémantiques auxquels le runtime doit réagir : challenges d'authentification, résultats de lookup, checksum mismatch, signaux de reconnexion ou transitions protocolaire. poll_timeout permet au runtime de savoir quand réveiller la machine d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La machine d'état ne décide pas d'où viennent les octets. Elle ne sait pas si le réseau est un vrai stream TCP, un stream TLS, un pipe d'octets dans un simulateur ou un broker scripté dans un harnais différentiel. Elle ne décide pas non plus ce que "maintenant" veut dire. Le moteur lui passe le temps.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les traits publics de magnetar-proto suivent la même règle. Ce ne sont pas des services runtime cachés derrière des callbacks async. Ce sont de petits contrats protocolaires, placés aux endroits où la machine d'état a besoin d'une décision ou d'une transformation : <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/auth.rs">AuthProvider</a> produit les octets d'authentification, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/schema/mod.rs">Schema</a> définit l'encodage, le décodage, les données de schéma et les hooks de schéma résolu par le broker, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/crypto.rs">MessageEncryptor et MessageDecryptor</a> décrivent la crypto de payload sur des octets et de la metadata de message, <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/service_url.rs">ServiceUrlProvider</a> expose l'URL de service courante pour le failover, et <a href="https://github.com/CleverCloud/magnetar/blob/main/crates/magnetar-proto/src/health_probe.rs">HealthProbe</a> utilise un contrat de type poll au lieu d'attacher le crate protocolaire à un runtime async. Le motif est volontaire : le coeur protocolaire peut demander des faits, des octets ou un état de readiness, tandis que l'I/O, le cache, le refresh, les probes réseau et le scheduler restent à l'extérieur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette séparation n'est pas seulement une affaire de propreté. C'est ce qui rend le protocole testable sans broker, sans socket et sans runtime async. Un bug protocolaire peut être réduit à une fixture : injecter ces octets à cet instant, récupérer ces sorties, vérifier cet event stream et rejouer la même séquence.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Pour un client Apache Pulsar, cela compte parce que le protocole wire ne se limite pas au chemin heureux. Il comprend la création de producers, la subscription de consumers, les acks, nacks, transactions, erreurs broker, redirects, challenges d'authentification, migrations de topics, markers de replicated subscriptions, metadata de schémas, batching, chunking et chemins de fermeture. Chacun de ces éléments porte de l'état. Chaque transition d'état est plus facile à raisonner lorsqu'elle n'est pas mélangée aux lectures de socket, au scheduling de tâches et aux wakeups spécifiques d'un runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">L'interdiction des channels comme contrainte d'architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar fait aussi un choix Rust async peu courant : les primitives de channels sont interdites dans le workspace.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'architecture directe d'un client réseau ressemble souvent à ceci : future producer vers channel, channel vers driver task, driver task vers channel, channel vers future consumer. Cela peut fonctionner, mais cela disperse l'état entre des files et des tâches. La backpressure devient implicite. Les sémantiques de fermeture dépendent de la bibliothèque de channel. Des futures abandonnées peuvent laisser des messages dans des endroits difficiles à inspecter. La question de debug devient : où est passé ce message ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar utilise un autre motif. L'état vit dans la machine d'état protocolaire et dans la connexion partagée détenue par le runtime. Les futures utilisateur enregistrent des wakers dans des slabs indexés par identifiants d'opération. Le driver possède la boucle d'I/O, injecte les octets dans la machine d'état, draine les frames sortantes et réveille les futures correspondantes lorsque les outcomes arrivent.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce n'est pas une interdiction esthétique des channels. C'est une manière de garder la propriété de l'état explicite. Lorsque le driver reconstruit des producers après une reconnexion, lorsqu'un consumer attend un message, lorsqu'un ack outcome est livré ou lorsqu'une opération en attente échoue parce qu'une session a disparu, l'état pertinent est dans la machine d'état et peut y être inspecté.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ce design a des compromis. Il met plus de pression sur la correction de la machine d'état. Il impose un ordre de locks précis. Il demande aux reviewers de comprendre l'enregistrement des wakers et les chemins de réveil. Mais il rend aussi le comportement beaucoup plus facile à simuler, rejouer et comparer entre runtimes.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Deux moteurs, une machine d'état</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar livre deux moteurs qui pilotent le même coeur protocolaire.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur par défaut est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-tokio">magnetar-runtime-tokio</a>. C'est le chemin d'exécution de production : TCP, TLS via tokio-rustls, tâches driver, temps réel, vraies sockets et surface publique PulsarClient que la plupart des utilisateurs rencontreront en premier.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le second moteur est <a href="https://github.com/CleverCloud/magnetar/tree/main/crates/magnetar-runtime-moonpool">magnetar-runtime-moonpool</a>. Il pilote la même machine d'état magnetar-proto::Connection à travers des providers Moonpool. Au lieu d'inscrire le runtime en dur, Moonpool expose des traits de providers pour le réseau, le temps, le spawning de tâches, l'aléa et le stockage. Avec un bundle de providers proche de la production, le moteur peut exécuter de vraies I/O. Avec des providers de simulation, ces mêmes catégories peuvent être virtualisées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est là que la simulation déterministe devient pratique. Le client peut être piloté dans un monde où le temps avance sous contrôle, où les livraisons réseau peuvent être réordonnées ou interrompues, où les tâches s'exécutent sous un scheduler déterministe, où l'aléa est seedé et où les pannes peuvent être rejouées depuis la même seed.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas un mock. Un mock remplace généralement un composant par un comportement simplifié. C'est utile pour beaucoup de tests unitaires, mais ce n'est pas la même chose que d'exercer un vrai client dans des interleavings difficiles.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool n'est pas non plus un test end-to-end classique. Un e2e exécute le vrai système, ce qui est indispensable, mais il utilise souvent du temps réel, un vrai réseau et des pannes difficiles à reproduire une fois le timing passé.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Moonpool occupe un autre espace. Il garde le code proche du chemin réel d'exécution tout en virtualisant les providers qui rendent le comportement distribué difficile à reproduire. Le but n'est pas d'éviter les e2e. Le but est d'ajouter un régime où les pannes ne sont plus des anecdotes. Elles deviennent des seeds.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le moteur Moonpool de Magnetar utilise la même machine d'état protocolaire que le moteur Tokio. Le chemin TLS est lui aussi piloté de façon à préserver la frontière de simulation : au lieu de s'appuyer sur tokio-rustls, le moteur Moonpool pilote directement rustls::ClientConnection au-dessus du pipe d'octets. Cela maintient les handshakes TLS sous le même contrôle déterministe que le reste du réseau simulé.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Tests différentiels : faire converger les moteurs</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Deux moteurs ne sont utiles que s'ils ne deviennent pas silencieusement deux clients différents.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar inclut donc un harnais différentiel. Il exécute une trace, par exemple connect, open producer, send, subscribe, receive, ack, seek et close, contre les moteurs Tokio et Moonpool, puis compare les event streams visibles par l'utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que le moteur Moonpool sert à trouver des bugs difficiles à exposer avec du temps réel et de vraies sockets. Pour que cette recherche ait du sens, le moteur simulé doit rester aligné avec le moteur de production à la frontière utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si Tokio et Moonpool divergent, le simulateur devient moins fiable. Si le harnais différentiel les maintient alignés, alors une seed rouge dans le monde simulé pointe beaucoup plus probablement vers une propriété réelle du client, et non vers une implémentation séparée réservée aux tests.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est aussi pour cela que la politique de validation de Magnetar est stricte sur la couverture cross-runtime. Les changements comportementaux doivent exercer la couche sans-io, le runtime Tokio, le runtime Moonpool, l'équivalence différentielle et la surface e2e lorsque c'est applicable. C'est plus de travail qu'un seul test unitaire. C'est aussi le coût pour faire de la simulation déterministe un vrai outil d'ingénierie, pas une expérience annexe.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La parité Java comme contrat de crédibilité</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La simulation ne remplace pas la largeur fonctionnelle. Elle rend cette largeur moins fragile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Apache Pulsar possède un <a href="https://pulsar.apache.org/docs/">client Java</a> mature, et pour beaucoup d'utilisateurs ce client définit ce que signifie "un client Pulsar". Le produce/consume de base ne suffit pas. Un client crédible doit couvrir les comportements sur lesquels les applications s'appuient : batching, compression, transactions, schémas, topics partitionnés, consumers multi-topics et par pattern, retries, dead-letter flows, providers d'authentification, support proxy, failover, opérations admin et PIPs qui structurent les usages modernes de Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar suit la parité avec le client Java comme un contrat public. Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> porte la matrice de parité et le statut moteur par moteur. L'article n'a pas besoin de recopier cette matrice, mais son existence est importante. Elle donne aux utilisateurs un moyen d'évaluer le projet comme client Pulsar, et non comme une expérience étroite autour d'un seul chemin heureux.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi la première release publique de Magnetar est plus large qu'une démo minimale. Elle inclut la fondation protocolaire, la façade publique, les moteurs runtime, le support admin, les providers d'authentification, la crypto de messages, le travail CLI, les hooks d'observabilité et une liste croissante de surfaces PIP.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La raison de suivre la parité est simple : les utilisateurs ne choisissent pas une bibliothèque cliente uniquement parce que son architecture interne est élégante. Ils la choisissent parce qu'elle peut représenter le système qu'ils exécutent réellement. L'architecture rend cette surface maintenable. La parité la rend utile.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Au-delà de la production et de la consommation</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>L'expression "client Pulsar" peut masquer une large surface fonctionnelle. Vus de l'extérieur, les premiers exemples paraissent généralement modestes : construire un client, créer un producer, envoyer un payload, souscrire avec un consumer, recevoir un message, l'acquitter. Ces exemples sont utiles parce qu'ils montrent le point d'entrée. Ils ne suffisent pas à évaluer le client.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les vraies applications Pulsar dépendent de comportements qui n'apparaissent qu'une fois la première démo fonctionnelle. Un producer peut avoir besoin de batching, de compression, de chunking, de modes d'accès, de sequence ids, de timeouts d'envoi, de propriétés par message, de transactions, d'interceptors et de statistiques de latence. Un consumer peut avoir besoin de batch receive, d'acquittements cumulatifs, d'acquittements par index de batch, de nack backoff, de gestion des timeouts d'ack, de retry topics, de dead-letter topics, de seek, de pause/resume, de modes de souscription et de comportements par partition. Les applications avec des schémas stricts ont besoin d'Avro, de JSON, de Protobuf, de Protobuf-native, de KeyValue, de schémas primitifs et de la sémantique de résolution de schéma côté broker. Les déploiements avec des exigences de sécurité ont besoin d'authentification par token, de mTLS, d'OAuth2, de SASL, de Kerberos/GSSAPI, d'Athenz, de choix de provider TLS, et d'un moyen de raisonner sur le comportement de la crypto sans forcer chaque build à embarquer tous les providers.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces fonctionnalités ne sont pas des cases à cocher indépendantes. Elles interagissent. Le batching interagit avec la compression et les timeouts d'envoi. Le chunking interagit avec les sequence ids et la redélivrance. Les transactions interagissent avec les acquittements. La reconnexion interagit avec les producers, les consumers, les lookups, le routage proxy et le failover. L'observabilité doit décrire le comportement sans laisser fuiter de secrets ni noyer les opérateurs en période de churn.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi le travail fonctionnel et le travail d'architecture de Magnetar sont liés. Plus la surface devient complète, plus il est important que l'état protocolaire soit explicite et que la frontière avec le runtime reste étroite. Un client large bâti sur un état accidentel devient plus difficile à maintenir à mesure qu'il devient plus utile. Un client large bâti sur un état rejouable donne aux mainteneurs une meilleure chance d'empêcher la croissance fonctionnelle de se transformer en comportement caché.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">La validation comme architecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La stratégie de test de Magnetar est volontairement stratifiée, parce que chaque couche attrape une classe différente de bugs.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La couche sans-io permet de tester le comportement protocolaire sans sockets ni tâches async. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">documentation de test du projet</a> mentionne aujourd'hui plus de 270 tests unitaires dans magnetar-proto. Ces tests exercent directement la machine d'état : octets en entrée, événements en sortie, buffers de transmission en sortie, transitions d'état vérifiées.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'intégration runtime exercent la colle que les tests purement protocolaires ne peuvent pas couvrir. Les moteurs Tokio et Moonpool ont chacun leur surface d'intégration, et le projet impose une parité runtime afin qu'un moteur ne prenne pas silencieusement du retard sur l'autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le pack de chaos déterministe cible les ordonnancements de panne qui ont motivé l'architecture : reconnect, failover, timers en horloge virtuelle, ordre des handshakes TLS, publishes en vol, migration de broker et comportements réseau adversariaux. La <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> décrit un sweep Moonpool quotidien avec 128 seeds aléatoires fraîchement générées en parallèle. Le chiffre compte moins que ce qu'il représente : le client est poussé dans des ordonnancements qu'un humain n'écrirait pas à la main.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests d'équivalence différentielle comparent les deux mondes runtime. Ils posent une question directe : si la même trace est exécutée dans Tokio et Moonpool, l'utilisateur observe-t-il le même comportement ?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les tests end-to-end restent nécessaires. Ils gardent Magnetar honnête face à un vrai broker Apache Pulsar. La simulation rend des pannes reproductibles, mais elle ne remplace pas la compatibilité avec le système que les utilisateurs déploient.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ensemble, ces couches ne sont pas une cérémonie. Elles font partie de l'architecture. Le but n'est pas d'accumuler de grands nombres de tests. Le but est d'appliquer la pression de validation exactement là où les clients distribués échouent : état protocolaire, frontières runtime, logique de reconnexion, timing, équivalence et comportement face à un vrai broker.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que la reproductibilité change concrètement</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>La valeur pratique de la simulation déterministe n'est pas seulement de rendre les tests plus sophistiqués. Elle change la boucle de debug.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lorsqu'un test end-to-end traditionnel échoue à cause du timing, la première question est souvent de savoir si l'échec est reproductible. S'il ne l'est pas, on ajoute des sleeps, des logs, des timeouts plus larges ou des boucles de retry. Certaines de ces modifications sont utiles. Beaucoup ne font que déplacer la panne ailleurs. La panne reste une histoire : "on l'a vue une fois en CI".</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Avec une simulation déterministe, la panne doit devenir un artefact. Cet artefact est une seed, une trace et une transition d'état rejouable. La question passe de "peut-on la refaire apparaître ?" à "quel invariant cet ordonnancement a-t-il violé ?"</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette différence compte pour une bibliothèque cliente. Les bugs de client se trouvent souvent à la frontière entre le code utilisateur et le broker. Ils sont faciles à attribuer au mauvais endroit. Un publish peut échouer parce que le broker a fermé la connexion, parce que le client a perdu un outcome, parce que le chemin de reconnexion a reconstruit le producer trop tard, parce qu'un ack a réveillé le mauvais waiter, parce qu'un timeout a frappé un état de session périmé, ou parce que la tâche runtime est morte après que le protocole a déjà changé d'état.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Si tout ce comportement est dispersé entre des tâches, des channels, des timers et des sockets, un rapport de panne est difficile à réduire. Si la machine d'état protocolaire est explicite, si la frontière runtime est étroite et si la même séquence peut être rejouée avec des providers contrôlés, le rapport devient beaucoup plus petit : cette seed, cette trace, cet ordre d'événements, cet invariant.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est pourquoi Magnetar traite la reproductibilité comme une partie du design du client. Le but n'est pas seulement de trouver plus de bugs. Le but est que les bugs trouvés coûtent moins cher à comprendre et soient plus sûrs à corriger.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela change aussi la revue de code. Un reviewer peut demander si un comportement est couvert à la bonne couche. Est-ce une transition protocolaire pure ? Alors le test sans-io doit injecter des octets et vérifier des événements. Est-ce de la colle runtime ? Alors Tokio et Moonpool doivent avoir une couverture équivalente. Est-ce un comportement observable partagé par les deux moteurs ? Alors le harnais différentiel doit comparer les event streams. Est-ce de la compatibilité broker ? Alors un e2e doit toucher un vrai broker Pulsar.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Ces questions sont plus précises que "a-t-on ajouté des tests ?" Elles relient le test au modèle de panne.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Par où commencer la lecture</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Pour les ingénieurs qui découvrent Magnetar, le meilleur point d'entrée n'est pas un fichier unique. C'est la relation entre les documents et le code.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> donne la surface publique : ce que le client expose, quelles fonctionnalités sont implémentées, comment la matrice de parité Java est suivie, quels PIPs sont supportés et comment les deux moteurs sont positionnés. C'est le contrat utilisateur.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> explique la forme située sous ce contrat. Il montre la topologie de crates, le sens des dépendances, la frontière sans-io, la boucle driver, le modèle d'événements, les chemins producer et consumer, les moteurs runtime, les sites TLS, les schémas, la couverture PIP et la stratégie de validation. C'est la carte du système.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>La <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">série d'ADR</a> explique pourquoi le système a cette forme. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">ADR-0004</a> documente la séparation sans-io. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0003-no-channels-rule.md">ADR-0003</a> documente l'interdiction des channels. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0011-clock-injection-sans-io.md">ADR-0011</a> documente l'injection d'horloge. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">ADR-0010</a> documente la décision de parité Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0019-engine-scope-and-moonpool-parity.md">ADR-0019</a> documente la relation entre le moteur de production Tokio et le moteur Moonpool par rapport à cet objectif de parité. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">ADR-0024</a> documente la politique de test cross-runtime.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cela compte parce que Magnetar n'est volontairement pas seulement un dépôt de code. C'est un ensemble de décisions d'ingénierie avec une trace publique. Si vous n'êtes pas d'accord avec le design, les ADR donnent la bonne surface de discussion. Si vous voulez contribuer une fonctionnalité, la matrice de parité et la politique de validation indiquent ce que "terminé" veut dire. Si vous voulez évaluer le travail de simulation, la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> et le harnais différentiel montrent comment le même coeur protocolaire est piloté dans plusieurs mondes.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cette première release doit donc se lire de deux manières. Comme utilisateur Pulsar, regardez la surface cliente et la matrice de parité. Comme ingénieur infrastructure Rust, regardez la frontière de machine d'état et la stratégie de simulation. Ce qui rend Magnetar intéressant, c'est que ces deux lectures sont censées se renforcer.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Ce que donne la première release publique</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Cette première release publique est un point d'entrée technique. Elle s'adresse aux ingénieurs qui veulent essayer Magnetar, lire l'architecture, inspecter les ADR, comparer le comportement avec les clients Pulsar existants et contribuer à structurer l'écosystème Pulsar Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>L'API cliente de haut niveau commence par une forme attendue :</p>
<!-- /wp:paragraph -->

<!-- wp:html -->
<div
  style="
    max-width: 780px;
    margin: 1.5rem auto;
    padding: 16px 20px;
    background: #0f172a;
    color: #e5eefc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Roboto, 'Helvetica Neue', Arial, sans-serif;
    font-size: 15px;
    line-height: 1.7;
  "
>
  <pre
    style="
      margin: 0;
      overflow-x: auto;
      white-space: pre-wrap;
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
        'Liberation Mono', 'Courier New', monospace;
    "
  ><code>let client = PulsarClient::builder()
    .service_url("pulsar://localhost:6650")
    .build()
    .await?;

let producer = client
    .producer("persistent://public/default/orders")
    .create()
    .await?;</code></pre>
</div>
<!-- /wp:html -->

<!-- wp:paragraph -->
<p>Cette API est importante, parce que le client doit être utilisable. Mais la release est aussi une invitation à inspecter les couches inférieures. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">README</a> pour la matrice fonctionnelle. Lire le <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">document d'architecture</a> pour le design sans-io. Lire les <a href="https://github.com/CleverCloud/magnetar/tree/main/specs/adr">ADR</a> pour les décisions derrière l'interdiction des channels, les moteurs remplaçables, l'injection d'horloge, la parité Java, la parité Moonpool, les choix de providers TLS et la validation cross-runtime. Lire la <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">documentation du moteur Moonpool</a> si la simulation déterministe appliquée à un vrai client réseau vous intéresse.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Le point important pour cet article est la direction : Magnetar est public pour que les ingénieurs puissent évaluer à la fois la surface cliente et le modèle d'ingénierie qui la porte.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Vous pouvez consulter la première release publique de Magnetar <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.0.0">v1.0.0</a>, ainsi que la dernière release à ce jour, la version <a href="https://github.com/CleverCloud/magnetar/releases#release-v1.2.0">v1.2.0</a>.&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Pourquoi cela dépasse Magnetar</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Magnetar est un client Apache Pulsar. C'est aussi un exemple concret de la manière dont nous voulons construire davantage de logiciel d'infrastructure en Rust.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Les systèmes distribués échouent par transitions d'état. Certaines de ces transitions sont évidentes et faciles à tester. Beaucoup ne le sont pas. Elles apparaissent lorsque le temps avance au mauvais endroit, lorsqu'un retry chevauche un chemin de fermeture, lorsqu'un broker coupe une connexion après avoir accepté une partie de la session, lorsqu'un callback est enregistré juste après une notification, ou lorsqu'un chemin de reconnexion reconstruit un handle mais pas un autre.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>On peut essayer de traquer ces bugs après coup. C'est parfois inévitable. Mais l'architecture peut rendre cette traque plus facile ou plus difficile.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Un client avec un coeur protocolaire pur, des événements explicites, du temps injecté, une I/O remplaçable, des seeds déterministes et une comparaison cross-runtime donne de meilleurs outils aux ingénieurs. Il permet de réduire une panne à une trace. Il permet de rejouer cette trace. Il permet de demander si une panne simulée correspond au runtime de production. Il permet d'ajouter un invariant là où une dérive silencieuse de l'état pouvait se cacher.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>C'est la direction prise par Magnetar. Rendre le protocole explicite. Rendre le runtime remplaçable. Rendre les pannes reproductibles. Faire de la correction quelque chose que le code doit démontrer en continu.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Merci à Pierre Zemb pour Moonpool et pour cette direction de simulation déterministe en Rust, ainsi qu'aux contributeurs et mainteneurs de l'écosystème Pulsar Rust dont le travail a rendu l'étape suivante possible.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Magnetar est open source. Le code, les notes d'architecture, les ADR et la documentation vivent sur <a href="https://github.com/CleverCloud/magnetar">github.com/CleverCloud/magnetar</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:html -->
<hr style="border: none; height: 1px; background-color: #ccc; margin: 32px 0;">
<!-- /wp:html -->

<!-- wp:spacer {"height":"25px"} -->
<div style="height:25px" aria-hidden="true" class="wp-block-spacer"></div>
<!-- /wp:spacer -->

<!-- wp:heading -->
<h2 class="wp-block-heading">Références</h2>
<!-- /wp:heading -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Magnetar</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>Dépôt Magnetar</strong>. Dépôt public du client Apache Pulsar Rust. <a href="https://github.com/CleverCloud/magnetar">https://github.com/CleverCloud/magnetar</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>README Magnetar</strong>. Surface publique, matrice de parité Java, PIPs supportés, couverture par moteur et statut. <a href="https://github.com/CleverCloud/magnetar/blob/main/README.md">https://github.com/CleverCloud/magnetar/blob/main/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Architecture Magnetar</strong>. Rationale sans-io, topologie de crates, driver loop, machine d'état protocolaire et tests. <a href="https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md">https://github.com/CleverCloud/magnetar/blob/main/ARCHITECTURE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Index de documentation Magnetar</strong>. Moteur Moonpool, testing, CLI, observabilité, logging, features PIP. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/README.md">https://github.com/CleverCloud/magnetar/blob/main/docs/README.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation du moteur Moonpool</strong>. Moteur de simulation déterministe, chaos pack, harnais différentiel, modèle de providers. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md">https://github.com/CleverCloud/magnetar/blob/main/docs/moonpool-engine.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Documentation de test</strong>. Catégories de tests et commandes de validation. <a href="https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md">https://github.com/CleverCloud/magnetar/blob/main/docs/testing.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0004</strong>. magnetar-proto sans-io et moteurs d'I/O remplaçables. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0004-sans-io-protocol-core.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0010</strong>. Parité complète avec le client Java. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0010-v0-1-full-java-parity.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>ADR-0024</strong>. Politique de tests et couverture cross-runtime. <a href="https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md">https://github.com/CleverCloud/magnetar/blob/main/specs/adr/0024-cross-runtime-test-and-coverage-policy.md</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Écosystème</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>pulsar-rs</strong>. Client Apache Pulsar Rust existant. <a href="https://github.com/streamnative/pulsar-rs">https://github.com/streamnative/pulsar-rs</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Apache Pulsar</strong>. Plateforme distribuée de messaging et streaming. <a href="https://pulsar.apache.org/">https://pulsar.apache.org/</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Client Java Apache Pulsar</strong>. Surface de référence pour de nombreux utilisateurs Pulsar. <a href="https://pulsar.apache.org/docs/">https://pulsar.apache.org/docs/</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading">Simulation déterministe</h3>
<!-- /wp:heading -->

<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li><strong>FoundationDB testing</strong>. Lignée de la simulation déterministe et de l'injection de fautes. <a href="https://apple.github.io/foundationdb/testing.html">https://apple.github.io/foundationdb/testing.html</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle TigerStyle</strong>. Style d'ingénierie centré sur les assertions. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>TigerBeetle VOPR</strong>. Approche de simulation testing. <a href="https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md">https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/internals/vopr.md</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Dépôt Moonpool</strong>. Simulation déterministe pour systèmes Rust, développée par Pierre Zemb. <a href="https://github.com/PierreZ/moonpool">https://github.com/PierreZ/moonpool</a></li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>moonpool-sim</strong>. Crate du moteur de simulation Moonpool. <a href="https://crates.io/crates/moonpool-sim">https://crates.io/crates/moonpool-sim</a></li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
