Fonctionnement distribué
Imaginez un core qui revient après une pause réseau et croit encore être leader. Un autre core a déjà renouvelé le lease. Le problème n'est pas seulement l'élection ; il faut empêcher l'ancien leader de commit.
Le distribué AppCore combine control plane, leases, discovery, Peer RPC, gateway mesh relay et providers de coordination explicites.
Le réseau privé n'est pas une authentification. Chaque node valide encore tenant, cluster, protocole, core cible, nonce, expiry, payload hash et liaison du credential.
Quel problème le control plane résout-il ?
Le file control plane prend un lock, recharge un état validé et borné, supprime les enregistrements expirés, applique une opération et persiste atomiquement.
Chaque opération :
- prend un file lock du système d'exploitation ;
- recharge un état validé et borné ;
- supprime les enregistrements expirés selon le clock autoritatif ;
- applique exactement une opération ;
- persiste atomiquement l'état résultant.
Le control plane enregistre presence, heartbeat, peer discovery et leadership par service. Son envelope durable possède format version et taille maximale ; une version incompatible échoue à l'update wall au lieu d'être devinée. Il répond qui est présent et qui détient un lease, mais ce n'est pas une database métier.
Il enregistre présence, heartbeats, discovery et leadership par service. Ce n'est pas une base métier. Son état durable possède une version de format et une taille maximale ; une version incompatible échoue explicitement.
Pourquoi l'élection ne suffit-elle pas sans fencing ?
Leadership est scoped par service_id. Un lease contient service, tenant, cluster, holder core, expiry et epoch. L'epoch est le fencing token.
Un ancien leader échoue lorsque :
- le lease a expiré ;
- le holder core diffère ;
- tenant ou cluster diffère ;
- l'epoch minimum demandé est plus récent que le lease courant.
L'élection choisit un holder ; le fencing empêche l'ancien travail de commit après un changement.
Un ancien leader qui se réveille avec un epoch périmé voit son commit rejeté par le guard. Cette protection distingue une élection observée de la garantie que l'ancien travail ne peut plus agir.
Pourquoi les providers sont-ils sélectionnés explicitement ?
Le Deployment Manifest sélectionne storage, control plane, coordination store, secret provider, jobs, discovery, update, database et transports. Les factories sont enregistrées par role et provider ID. Une paire absente échoue ; aucun fallback de distant vers local, cluster vers standalone ou sûr vers non sûr.
Que valide Peer RPC avant le dispatch ?
L'envelope lie :
- request ID ;
- trace ID et trace context facultatif ;
- protocol version ;
- source core ;
- target core ;
- tenant ;
- cluster ;
- timestamp et expiry ;
- nonce ;
- capability ;
- body hash ;
- idempotency key facultative.
Peer RPC valide request ID, trace, protocole, source/target core, tenant, cluster, timestamp, expiry, nonce, capability, body hash et idempotency key optionnelle. Le nonce store peut être en mémoire ou sur fichier privé, borné, verrouillé et remplacé atomiquement.
La validation borne aussi le payload et contrôle protocol, fenêtre temporelle, cohérence du trace et replay du nonce. Le token peer peut se lier au hash complet de la request afin qu'un bearer token ne serve pas pour un autre routing ou body.
Les rejets V2 sont typés et bornés. Un code fixe détermine phase et si une opération idempotente de niveau supérieur peut retenter; le peer ne déclare pas retryability indépendamment. Des métadonnées inconnues ou contradictoires échouent de façon conservatrice. V1 conserve le champ string, mais le client ne reconnaît que les codes contrôlés exacts et n'interprète jamais de sous-chaîne. La sélection V2 est une décision de deployment explicite et coordonnée; les peers V1 ne sont ni mis à niveau ni redirigés.
Pourquoi le Gateway existe-t-il ?
Gateway existe pour les cores sans port entrant stable. Il relaie et route, mais n'interprète jamais le payload métier opaque.
L'activation Gateway est déclarative. Quand le Deployment Manifest sélectionne
l'adapter, l'exécutable de déploiement valide la configuration, ajoute et autorise
runtime.gateway dans le catalogue partagé, réutilise la sécurité Runtime et
enregistre le Gateway comme service critique du Supervisor :
[adapters.gateway]
provider_id = "appcore-gateway"
settings = { bind_address = "127.0.0.1:8080", domain_suffix = "gateway.example.com", heartbeat_interval_ms = "30000", heartbeat_timeout_ms = "90000" }
secret_refs = {}
Seuls ces quatre settings non secrets sont acceptés. Settings inconnus, endpoints, références de secret et overrides d'authentification échouent fermés. Sans l'adapter, aucun listener ni task Gateway n'est créé ; une configuration ou un bind invalide arrête le startup.
Les tokens worker et client sont courts, à usage unique et liés à un hash. Le hash worker couvre tenant, cluster, installation, core et capabilities ; celui du client couvre tenant, cluster et device. Le relay vérifie la concordance de la metadata externe avec l'envelope Peer RPC puis borne messages, timeouts et files sans interpréter le payload opaque.
Le host utilise un replay store durable et sûr entre processus. Standalone le
place dans le storage privé ; cluster exige un paths.gateway_replay absolu
vers un fichier inscriptible partagé par toutes les instances. Les sockets
expirent en 60 secondes maximum et le shutdown borné ferme les connexions
incomplètes.
Limitations
- Le file control plane est une référence pour répertoire partagé, pas un consensus global.
- Les leases exigent TTLs et horloges configurés prudemment.
- Peer RPC authentifie l'enveloppe runtime ; l'autorisation métier appartient à l'application.
- Gateway relaie des payloads opaques et ne résout pas les conflits.
- Gateway en cluster échoue fermé sans replay file partagé explicite.
- Provider absent échoue le startup ; AppCore ne bascule pas vers une option plus faible.
Suivant : supervisor.
Migration du transport applicatif
Versions d'enveloppe/schema applicatif, wire sync et transport Peer RPC sont indépendantes. Streaming V2 ne modifie ni schema métier ni réplication leader-follower. Chunks/streams existent déjà ; migrer exige des adaptateurs applicatifs externes explicites.
Mapping et contrat de deployment
| Frontière applicative | Frontière streaming | Responsabilité conservée |
|---|---|---|
| Négociation / status V1 | Query de capability applicative versionnée | Déclarer transport supporté ; absence signifie non éligible V2 |
IngestChunkV1 | Stream open/chunk/commit vérifié avec payload applicatif | Adaptateur externe reconstruit/valide octets, identité, séquence et digest |
PullRequestV1 / PullChunkV1 | Command/query explicite et réponse pull bornée | Conserver curseur, checkpoint et autorisation hors frames |
| Pages snapshot / événements | Payloads opaques bornés | Application valide schema et publie seulement un résultat complet vérifié |
Le package de protocole externe doit contenir le mapping et les fixtures golden. Conserver
les endpoints applicatifs V1 pour anciens clients seulement dans ce package.
Runtime V1 n'infère pas V2, ne lit pas d'enveloppes supprimées et ne convertit
pas les formats applicatifs. Les entrées Runtime supprimées retournent toujours
NO MORE SUPPORTED PLEASE UPDATE.
Migration par étapes
- Inventorier versions installées, identités, scopes, limites, retries et outboxes/checkpoints persistés. Garder fixtures V1 dans le dépôt applicatif ; aucun schema métier dans Runtime.
- Ajouter une capability versionnée explicite à l'adaptateur externe.
Configurer
PeerRpcStreamRegistrydans un spool existant owner-only et installer viaPeerRpcHttpHost::with_v2_stream_registry. Définir budgets par capability ; valider tenant, cluster, origine et cible avant dispatch. - Les clients applicatifs V1 gardent leur chemin explicite actuel. Sélectionner
V2 après négociation validée ou setting deployment explicite. L'hôte Runtime
par défaut reste V1. JSON canonique V2 est distinct du binaire : ce dernier
exige hôte
with_v2_binary_codecet clientwith_stream_codec_v2(PeerRpcStreamCodecV2::Binary)ensemble. - Prouver payload/résultat et checkpoints équivalents par transport. Tester timeout, annulation, replay, duplication, corruption, oversize, isolation, perte de pair et commit ambigu. Ne pas répéter automatiquement les frames après panne ambiguë ; réconcilier receipts avec la même clé d'idempotence.
- Déployer les receivers d'abord, puis senders sélectionnés. Observer codes sûrs, saturation, nettoyage du spool et retard checkpoint. Cohortes explicites ; aucun downgrade silencieux après erreur d'authentification ou media type.
- Rollback : arrêter nouveaux sends V2, drainer/expirer sessions, réconcilier receipts et préserver outboxes/checkpoints. Reprendre l'adaptateur externe V1 explicitement avec schema/état compatibles. Persistance incompatible exige plan version/migration/rollback revu ; ni effacement ni conversion inférée.
Preuves de conclusion
Preuves applicatives : ancien client/nouveau receiver, nouveau sender/nouveau receiver, paire ancienne choisie explicitement et refus contrôlé des paires non supportées. Exiger payloads golden équivalents, replay sans publication double, aucune réservation pending permanente après erreur, aucun snapshot partiel, ressources bornées et recovery après restart. Les tests Runtime certifient les primitives, pas le mapping externe. Ce document ne fournit pas l'adaptateur.
Durabilité du nonce et diagnostic typé
Sous Windows, la publication du nonce synchronise le fichier puis utilise MOVEFILE_WRITE_THROUGH ; elle ne rouvre pas le parent comme répertoire Unix. Unix conserve le sync du parent. PeerRpcDiagnosticV2::from_wire conserve code, phase, retry et corrélation validés, une identité de peer fiable et une action définie par le protocole. Les codes inconnus restent expurgés et terminaux. Une expiration suggère de vérifier deadline/horloge sans prouver une dérive. Une suggestion de retry ne permet jamais le replay d’un command dont l’ack est ambigu. Projection locale additive ; les champs wire V1/V2 restent inchangés.
Progrès indépendant des peers et de la file
OperationalProjectionV1 expose séparément santé locale, accès Gateway, persistance, phase d’envoi et au plus 1 024 peers. Enregistrement n’implique ni connexion ni santé ; la portée de découverte ne promet pas de roster global complet. Batches pending et nombre optionnel d’objets sont distincts. L’âge heartbeat/file vient du temps monotone local écoulé ; l’horloge murale sert uniquement aux timestamps d’affichage. validate refuse identités dupliquées/excessives, versions futures et checkpoints au-delà du head observé ; lag reste inconnu sans preuves. Authentifiez et filtrez les inputs par tenant avant export. Associez PeerRpcDiagnosticV2 validé pour le dernier échec de transport. Aucun redémarrage de service ni supervision de processus OS.
Preuves de routing Gateway
GatewayError::diagnostic_v1 exporte catégorie contrôlée et corrélation bornée sans détail brut d’authentification/provider. Utilisez GatewayFailureDiagnosticV1::from_selection avant de réduire WorkerSelectionError en texte pour conserver worker absent, non sain et sans capacité. WorkerUnavailable général reste général ; aucune cause n’est déduite du texte. Retry exige des opérations idempotentes sûres et n’autorise aucun replay de command ambigu.
Liaison explicite de l’opération au token V2 pour les envelopes V1
Profil d’authentification additif non publié : sélectionnez with_v1_operation_binding_v2 sur PeerRpcClient et PeerRpcHttpHost. operation_signing_hash_v2 lie un domaine V2 explicite, query/command et le digest complet de l’envelope V1 existante. Schéma, numéro de protocole et routes V1 restent inchangés ; le contrat de liaison du token est explicitement V2. Aucun côté ne négocie, ne déduit ni n’accepte un digest alternatif. Des profils différents échouent à l’authentification. Health/manifest et streaming V2 conservent leur authentification.
Le profil V1 publié par défaut conserve seulement l’envelope pour la stabilité contractuelle et ne lie pas cryptographiquement la classe de route. Sélectionnez le profil avec opération ou streaming V2 lorsque cette frontière compte ; le dispatcher doit toujours autoriser capability et mode d’invocation. Mettez à jour les deux endpoints atomiquement ou déplacez le trafic vers un host configuré séparément. Drainez d’abord les commands ambigus. Le rollback restaure explicitement les sélections des deux côtés ; ne répétez pas un command au reçu incertain avec une nouvelle clé. Cette modification ne certifie ni ne publie une migration d’installation.
Disponibilité HA négociée — RC 2026-11-09
Le profil optionnel peer.availability.v1 est annoncé dans les métadonnées avec la
valeur "1" lorsque le déploiement installe PeerOperationProfileV1 avec
PeerRpcHttpHost::with_availability_profile. command_with_availability utilise
/v2/peer/availability/command uniquement pour cette capacité. Sinon, le contrat V1
reste inchangé et retourne NegotiatedPeerOperationV1::V1; un succès ancien
ne devient pas un reçu durable. Aucun repli après sélection du profil. Les commandes
V1 utilisent le même exécuteur durable; le dispatcher de requêtes reste inchangé.
Catégories stables : busy { retry_after_ms }, recovery_pending, standby,
lease_renewal_failed, replica_commit_failed, authority_unavailable,
transport_unavailable, authentication_failed, protocol_mismatch.
AvailabilityErrorV1::retry propose un délai borné avec jitter fourni par l'appelant :
attente courte pour busy, sondage du rôle/disponibilité pour récupération/standby/lease,
sondage de confirmation pour réplica, circuit ouvert par route pour autorité/transport,
arrêt pour authentification/protocole. L'appelant conserve budget, circuit et prochaine
tentative persistée. Chaque appel effectue une tentative sans attente ni verrou global;
les opérations indépendantes restent possibles.
PeerOperationCallErrorV1 distingue les erreurs locales de transport/authentification/
protocole. Le résultat distant authentifié PeerOperationOutcomeV1 distingue
Rejected, Pending et Confirmed; seul le dernier porte un DurableOperationReceiptV1.
Aucune erreur technique ni attente ne permet de retirer une opération de l'outbox.
Après perte de réponse, réconcilier la même identité idempotente avec un nouveau nonce;
ne jamais réexécuter aveuglément la closure faute de confirmation ou de réponse.
PeerOperationExecutorV1 appartient au déploiement. Il doit indexer par
operation_identity_hash, rejeter un autre operation_binding_hash pour la même clé,
retrouver les résultats précédents, appliquer le fencing de l'autorité actuelle et
persister ensemble la fin de la closure et la politique/preuve durable dans sa frontière
de récupération. from_completed_commit vérifie seulement la structure des digests :
l'appeler après achèvement et confirmation durable. Un reçu d'histoire canonique ne
prouve pas les effets métier. Le Runtime ne certifie pas les transactions d'un provider.
L'authentification lie profil, commande et enveloppe complète. Toute réponse structurée, y compris busy, authentifie résultat, rôle/disponibilité et hash exact de la tentative. Utiliser des claims distinctes pour requêtes/réponses et vérifier TLS. Ingress partage 16 slots par host et dispatch 16 slots par processus. Une surcharge avant lecture du corps ou une requête non authentifiée ne produit pas de continuation authentifiée : erreur locale de transport/authentification. Busy après admission authentifiée n'appelle pas l'exécuteur et ne produit aucun ACK.
PeerOperationObserverV1 reçoit catégorie, délai busy, durée monotone, tentatives
(une par appel), rôle et disponibilité contrôlés. Aucun URL, token, chemin, identifiant,
digest ou payload; le callback doit être borné et non bloquant. Le relay Gateway utilise
la capacité métier de l'enveloppe interne et préserve le corps signé. Le SDK expose
les résultats et catégories avec sync, sans dépendre du client HTTP. Les clients,
hosts et observateurs restent dans appcore-peer-rpc.
L'adoption exige un adapter durable et la composition du déploiement. L’adoption exige des versions explicites; aucun changement des installations
existantes ou ACK de transport de FollowerSyncClient.
Les tests de récupération utilisent une preuve synchronisée et une véritable outbox
sur fichier; ils ne certifient pas les coupures électriques.