Comment j'ai architecturé une plateforme SaaS avec ActualLab Fusion
Retour d'expérience sur l'utilisation d'ActualLab Fusion pour éliminer REST et construire une architecture 100% réactive avec cache automatique et invalidation en cascade.
Le problème avec REST
Quand j'ai commencé à architecturer OneRP — une plateforme SaaS distribuée pour GTA V — je me suis vite heurté aux limitations classiques de REST. Avec 250 joueurs simultanés générant des milliers d'événements par seconde (déplacements, inventaire, économie, chat), le pattern request-response devenait un goulot d'étranglement.
Le constat : 80% de mes appels REST étaient des lectures répétitives. Le serveur recalculait les mêmes données à chaque requête. Polling toutes les secondes sur 44 services ? Impensable.
La découverte de Fusion
ActualLab Fusion change fondamentalement la donne. Au lieu de REST endpoints, vous déclarez des ComputeMethod — des méthodes dont le résultat est automatiquement mis en cache et invalidé quand les données sous-jacentes changent.
[ComputeMethod]
public virtual async Task<PlayerEconomy> GetPlayerEconomy(int playerId)
{
var player = await _db.Players.FindAsync(playerId);
var accounts = await _db.BankAccounts
.Where(a => a.PlayerId == playerId)
.ToListAsync();
return new PlayerEconomy(player, accounts);
}
Ce qui se passe en coulisses :
- Premier appel → calcul réel, résultat mis en cache
- Appels suivants → cache servi instantanément
- Quand
BankAccountschange → invalidation automatique → recalcul - Tous les clients connectés reçoivent la mise à jour via WebSocket
Zero polling. Zero REST. Push automatique.
L'architecture résultante
Après 3 mois de développement intensif, voici les chiffres :
- 44 ComputeServices couvrant économie, inventaire, véhicules, propriétés, métiers...
- 0 endpoint REST — 100% Fusion RPC via WebSocket
- Cache hit rate > 95% en conditions normales
- Latence < 50ms pour les mises à jour push
Le graphe d'invalidation est le cœur du système. Quand un joueur achète un objet :
InventoryService.GetInventory()est invalidé- Ce qui invalide
PlayerService.GetPlayerWeight() - Ce qui invalide
UIService.GetHUDData() - Le HUD du joueur se met à jour automatiquement
Multi-tenancy avec Fusion
L'autre défi était le multi-tenant. Chaque serveur GTA V est un tenant isolé. La solution : combiner les Global Query Filters d'EF Core avec le cache Fusion.
// Le TenantProvider injecte automatiquement le filtre
modelBuilder.Entity<Vehicle>()
.HasQueryFilter(v => v.ServerId == _tenantProvider.CurrentServerId);
Fusion cache les résultats par clé composite (tenantId, playerId), donc pas de fuite de données entre tenants même avec le cache.
Ce que j'en retiens
Fusion n'est pas pour tout le monde. La courbe d'apprentissage est raide, la documentation est sparse, et vous devez repenser complètement votre architecture. Mais pour un système où les données changent fréquemment et doivent être poussées aux clients en temps réel, c'est imbattable.
J'ai depuis réutilisé cette architecture sur SaleCast (e-commerce, 185 entités) et PromptVault (SaaS de prompts IA). À chaque fois, la suppression de REST a simplifié le code et éliminé des classes entières de bugs.
Le futur du web est réactif, pas request-response.
Florian Sola
Lead Technique · Haute performance temps réel · 9 ans d'expérience