Limitations de la plateforme
Mis à jour le 29 juillet 2026
Connaître les limites
La plateforme Workflows de Mistral est en Public Preview (avril 2026). Comme tout système d’orchestration, elle impose des limitations techniques qu’il est essentiel de connaître pour concevoir des workflows robustes. Ces limites ne sont pas des détails de documentation : elles se manifestent en production, souvent tard, sous la forme d’erreurs de sérialisation ou de workflows terminés de force que rien dans votre code ne laissait présager. Les connaître à l’avance change la façon dont vous découpez vos traitements.
Le tableau ci-dessous rassemble l’essentiel, avec pour chaque limite la conséquence concrète d’un dépassement.
| Limitation | Valeur | Conséquence si dépassée |
|---|---|---|
| Délai entre activités | 2 secondes | Latence incompressible entre chaque appel d'activité |
| Input/output par invocation | 2 MB | Erreur de sérialisation, workflow échoue |
| Événements par exécution | 51 200 | Workflow terminé de force |
| Taille totale par exécution | 50 MB | Workflow terminé de force |
| Timeout par défaut | 1 heure | Workflow annulé (configurable jusqu'à 7 jours) |
| Timeout maximum | 7 jours | Workflow annulé automatiquement |
| I/O dans les workflows | Interdit | Erreur de non-déterminisme lors du replay |
Deux secondes entre chaque activité
La plateforme impose un délai minimum de 2 secondes entre deux appels d’activité. Cette latence n’est pas un défaut de jeunesse : elle est inhérente à l’architecture d’orchestration, qui persiste chaque événement avant de poursuivre. C’est le prix de la durabilité.
L’impact est facile à calculer et surprend souvent. Un workflow qui enchaîne dix activités séquentielles consomme au minimum vingt secondes d’orchestration, indépendamment du temps que prennent les activités elles-mêmes. Si chacune s’exécute en cinquante millisecondes, vous avez conçu un traitement d’une demi-seconde qui met vingt secondes à rendre son résultat.
La parade consiste à regrouper dans une seule activité les opérations qui n’ont pas besoin d’être séparées. Comparez ces deux versions d’un même pipeline NLP.
# SOUS-OPTIMAL : 3 activités = 6 secondes de latence d'orchestration
@workflows.workflow.define(name="pipeline_lent")
class PipelineLent:
@workflows.workflow.entrypoint
async def run(self, texte: str) -> dict:
tokens = await tokeniser(texte)
embeddings = await calculer_embeddings(tokens)
clusters = await clusteriser(embeddings)
return clusters
# OPTIMISÉ : 1 activité = 2 secondes de latence d'orchestration
@workflows.activity()
async def traitement_nlp_complet(texte: str) -> dict:
tokens = tokeniser_local(texte)
embeddings = calculer_embeddings_local(tokens)
clusters = clusteriser_local(embeddings)
return {"clusters": clusters}
@workflows.workflow.define(name="pipeline_rapide")
class PipelineRapide:
@workflows.workflow.entrypoint
async def run(self, texte: str) -> dict:
return await traitement_nlp_complet(texte)
Le critère de découpage devient alors simple à énoncer : ne créez une activité séparée que si vous avez besoin de la garantie de persistance entre deux opérations. Si deux opérations peuvent échouer ensemble sans que cela pose problème — ici, une tokenisation locale et un calcul d’embeddings enchaînés en mémoire — regroupez-les.
Deux mégaoctets par invocation
Chaque appel d’activité est limité à 2 MB en entrée et 2 MB en sortie, limite qui porte sur la représentation JSON sérialisée des données. Un PDF de rapport, un jeu d’images ou un export CSV volumineux la franchissent sans effort, et le workflow échoue avec une erreur de sérialisation.
La solution tient en une phrase : faites transiter des références, jamais des charges utiles. L’activité télécharge la donnée depuis un stockage externe, la traite localement où elle n’est bornée que par la mémoire du worker, puis renvoie l’URL du résultat.
@workflows.activity()
async def traiter_gros_fichier(fichier_url: str) -> dict:
"""Télécharge, traite et re-upload le fichier.
Seules les URLs transitent par le workflow."""
async with httpx.AsyncClient() as client:
# Télécharger depuis S3/GCS
response = await client.get(fichier_url)
contenu = response.content # Peut faire 100 MB
# Traiter le fichier
resultat = traiter(contenu)
# Uploader le résultat
await client.put(
"https://storage.example.com/résultats/output.json",
content=resultat
)
return {"url_resultat": "https://storage.example.com/résultats/output.json"}
Le budget d’événements et de volume
Chaque exécution est plafonnée à 51 200 événements. La plateforme en génère un à chaque démarrage d’activité, chaque complétion d’activité, chaque signal reçu et chaque timer déclenché. En pratique, un appel d’activité coûte environ deux à trois événements une fois les métadonnées comptées, ce qui met un workflow de cent activités aux alentours de 250 à 300 événements. Autrement dit, le plafond autorise quinze à vingt mille appels d’activité par exécution : largement au-delà de ce que réclame la plupart des cas d’usage.
Vous ne rencontrerez donc cette limite que sur des traitements de masse — parcourir cinquante mille documents dans une seule exécution, par exemple. Le pattern de continuation, détaillé dans la leçon suivante, résout ce cas : le workflow traite un lot, puis lance un nouveau workflow pour le lot suivant, remettant le compteur d’événements à zéro.
La seconde borne porte sur le volume : la taille cumulée de tous les événements d’une exécution ne doit pas dépasser 50 MB. Elle se remplit d’autant plus vite que vos activités renvoient des objets riches, puisque chaque résultat est écrit dans le journal. Le même réflexe s’applique — retourner un identifiant plutôt qu’une structure complète, stocker les résultats intermédiaires dans un service externe, paginer les traitements en lots — et il suffit dans l’immense majorité des cas.
Aucune I/O dans le workflow
La dernière ligne du tableau n’est pas une limite de dimensionnement mais une règle de conception, déjà rencontrée avec le déterminisme. Le code du workflow ne doit contenir aucune opération d’entrée/sortie : ni appel réseau (httpx, aiohttp, requests), ni lecture ou écriture de fichier (open, aiofiles), ni accès base de données, ni lecture de variables d’environnement destinée à orienter un branchement. Toutes ces opérations vivent dans les activités, dont les résultats sont journalisés et donc rejouables à l’identique.
Points clés à retenir
- 2 secondes de latence minimum entre chaque activité — regroupez les opérations liées
- 2 MB maximum par input/output d’activité — utilisez un stockage externe pour les données volumineuses
- 51 200 événements et 50 MB maximum par exécution — utilisez le pattern de continuation pour les très longs workflows
- Aucune I/O dans le code du workflow — tout va dans les activités
- Ces limitations sont liées à l’architecture Temporal sous-jacente et à la Public Preview